I am creating a booking application and have normalised the database as much as is possible. My question is the following, should I create Views in the database that combine the tables again before I do selective selects on the combined view in the WHERE clause or is it better to filter the tables with selects before joining them in a view?
EDIT: Included example.
The first scenario creates the combined view first, and then performs the SELECT on the combined view (this view may have thousands of records):
CREATE VIEW appc as
SELECT * FROM appointment
LEFT OUTER JOIN chair
ON appointment.chair_idchair = chair.idchair
SELECT * FROM appc
WHERE chair_idchair = 1;
The second scenario will first filter the table in the left of the join and then create a view based on the filtered table, then the join will be made using this much smaller view:
CREATE VIEW appf as
SELECT * FROM appointment
WHERE chair_idchair = 1;
SELECT * FROM appf
LEFT OUTER JOIN chair
ON appf.chair_idchair = chair.idchair
It makes little difference to MySQL. MySQL (unlike some other RDBMS brands) does not store anything in the view itself. Think of a MySQL view more like a macro. In most cases, querying the view is exactly like executing the query you defined as the view.
Applying subsequent conditions in the WHERE clause when querying the view is combined pretty transparently with the view's query, as if you had written the full query and given it one more condition.
Exception: you can optionally create the view with ALGORITHM=TEMPTABLE, to force it to store the results of the view in a temp table, and then apply extra conditions you specified in your query. In this case, it would be better to build the conditions into the view's query, to reduce the size of the resulting temp table.
See http://dev.mysql.com/doc/refman/5.6/en/view-algorithms.html for more details.
As a general rule, the optimizer is pretty smart, and can see right through the views when constructing a query plan. If you try to "help" the optimizer by pre-selecting some data, you may be hiding information from the optimizer that would have allowed it to create a smarter, more-optimal plan.
Related
I have a scenario where I have the following tables:
Inventories
delivery_items
deliveries
I seek a query where, having the inventory id, I get the delivery_item(fk_inventory),
which then I get the delivery from the (fk_delivery).
Manually, I go to the delivery_items table, then I search for the fk_inventory that matches the id from the inventory that I'm looking for,
then I get the fk_delivery, and get the delivery.
But I need to run a report on 15k+ items.
How to write a query where from a list of inventory ids I can get to the delivery following the relationship that I mentioned above?
There are many sites on writing SQL queries, differentiating between a normal (inner) join vs outer join, left join, right join, subqueries, etc. What you are looking to do is probably best (due to all inventory items in question) is simple joins.
Try to think of it this way, and maybe do it this way. Have a sheet of paper, one representing each table and write the columns on it.
Now, visually looking at the available tables, put them next to each other based on how they are related. Note the column in table A that is the foreign key to the next table. Then again, from the second to the third.
Once you have this done (or even if just mentally), you can SEE how they are related. This is the basis of the FROM clause
select *
from
YourFirstTable yft
JOIN YourSecondTable yst
on yft.WhateverKey = yst.MatchingKeyColumn
JOIN YourThirdTable ytt
on yst.KeyToThirdTable = ytt.KeyInThisTable
Now that you have all your relationships established, you can always declare the individual columns you want from those respective tables. Easier to use with the aliases such as I provided here via yft, yst, ytt representing the first, second and third tables. Use aliases appropriate to your tables such as i=inventories, di = delivery_items, d = deliveries.
Then add whatever FILTERING conditions you want. If the condition is based on the FIRST Table such as yft above, that would go into the WHERE clause such as
where
yft.SomeColumn = 'blah'
If the filtering criteria is specific to your second or third table, just add that to the JOIN / ON condition so it stays with the table and you know contextually it is associated HERE. It makes it easier when you are getting into LEFT JOINs.
from
YourFirstTable yft
JOIN YourSecondTable yst
on yft.WhateverKey = yst.MatchingKeyColumn
AND yst.SecondTableColumn = 'someOtherValue'
AND yst.SomeOtherColumn = 'somethingElse'
So now, the engine can go through all inventory items, to the corresponding details, to the actual deliveries without having to do individual searches each time which would be painful to trace / run / and performance.
I want to use a table that would be accessible under two names (something like e-mail address alias) i.e. I want queries:
select * from my_table_name
and
select * from my_alt_table_name
return records from the same table.
I know I can use a view and then run query on view, but wouldn't it be less efficient?
I know I can use a view and then run query on view, but wouldn't it be less efficient?
If the view is strictly SELECT * FROM table, without any additions (WHERE and so on), then there is no difference does you use the table or the view as an alias.
See small DEMO.
See SHOW WARNING outputs - they claims that the server is smart enough for to understand that it may/must use the table itself.
See EXPLAIN outputs - they claims that the server is smart enough for to understand that it may/must use the index which is present in the table structure.
expanded DEMO fiddle - analyse it by itself.
Also study CREATE VIEW Statement, ALGORITHM clause, and View Processing Algorithms. Try to add ALGORITHM = TEMPTABLE to DEMO and investigate the changes.
You can't have a table with multiple names, so yeah, just use views. There will be no impact on performance during the runtime, however during the compilation of the query, there will be just a small delay time for the compilation of the view to be transformed into a table in memory which is absolutely negligible
CREATE VIEW table_name_alias AS SELECT * FROM table_name;
SELECT * FROM table_name_alias;
Creating a view would look like this
CREATE VIEW my_alt_table_name AS SELECT * FROM my_table_name;
and next time you can use it like this
SELECT * FROM my_alt_table_name ;
I have a view which has the below definition
create view mydashboard as
SELECT distinct
cu.CrimeID,
ad.DeptID,
ad.CrimeDate,
cd.DeptIncidentID,
ad.crime,
u.username
from alldatescrimes ad
inner join crimeslist cl
on
ad.crime = cl.crime
inner join users u
on
u.DeptID = ad.DeptID
left join crimelookup cu
on cu.CrimesListID = cl.CrimeListID
left join crimesdetail cd
on
ad.CrimeDate = cast(cd.CrimeDate as date)
and
ad.DeptID = cd.DeptID
and
cu.CrimeID = cd.CrimeID
My problem is that If I put a where clause outside the view, the query runs very slowly. See the below example
select *
from mydashboard
where
(username = 'john'
or
DeptIncidentID is null
)
and
CrimeDate = '2014-06-16'
On the contrary If I put the same where clause inside the view, the query runs very fast..like in 2-3 seconds
My question is what steps can I take so that the query runs fast if I put the where clause outside view. I am using this view in a report and the query runs real slow
Regards
Arif
MySQL has two options to process a view that is used inside a query: MERGE or TEMPTABLE.
For MERGE, the text of a statement that refers to the view and the view definition are merged such that parts of the view definition replace corresponding parts of the statement.
For TEMPTABLE, the results from the view are retrieved into a temporary table, which then is used to execute the statement.
Because of the DISTINCT clause in the view definition, MySQL cannot use the MERGE algorithm. It must falback to the less efficient TEMPTABLE algorithm.
The temporary table has no index, therefore the whole table must be scanned to process your outer WHERE conditions.
You may want to remove the DISTINCT clause from the view definition, and put it in your outer query instead.
This is a bit long for a comment.
MySQL does a poor job of optimizing views. In fact, one part of the documentation starts:
View processing is not optimized:
One possible issue is that MySQL has determined that a temporary table is needed for the view. If so, all the processing needs to be done. Then at the very last stage, the where clause is being added. Here is more information on "merge" versus "temporary tables" for views.
I have created a complex view which gives me output within a second on Oracle 10g DBMS.. but the same view takes 2,3 minutes on MYSQL DBMS.. I have created indexes on all the fields which are included in the view definition and also increased the query_cache_size but still failed to get answer in less time. My query is given below
select * from results where beltno<1000;
And my view is:
create view results as select person_biodata.*,current_rank.*,current_posting.* from person_biodata,current_rank,current_posting where person_biodata.belt_no=current_rank.belt_no and person_biodata.belt_no=current_posting.belt_no ;
The current_posting view is defined as follows:
select p.belt_no belt_no,ps.ps_name police_station,pl.pl_name posting_as,p.st_date from p_posting p,post_list pl,police_station ps where p.ps_id=ps.ps_id and p.pl_id=pl.pl_id and (p.belt_no,p.st_date) IN(select belt_no,max(st_date) from p_posting group by belt_no);
The current_rank view is defined as follows:
select p.belt_no belt_no,r.r_name from p_rank p,rank r where p.r_id=r.r_id and (p.belt_no,p.st_date) IN (select belt_no,max(st_date) from p_rank group by belt_no)
Some versions of MySQL have a particular problem with in and subqueries, which you have in this view:
select p.belt_no belt_no,ps.ps_name police_station,pl.pl_name posting_as,p.st_date
from p_posting p,post_list pl,police_station ps
where p.ps_id=ps.ps_id and p.pl_id=pl.pl_id and
(p.belt_no,p.st_date) IN(select belt_no,max(st_date) from p_posting group by belt_no)
Try changing that to:
where exists (select 1
from posting
group by belt_no
having belt_no = p.belt_no and p.st_date = max(st_date)
)
There may be other issues, of course. At the very least, you could format your queries so they are readable and use ANSI standard join syntax. Being able to read the queries would be the first step to improving their performance. Then you should use explain in MySQL to see what the query plans are like.
Muhammad Jawad it's so simple. you have already created indexes on table that allow database application to find data fast, but if you change/update the (indexes tables) table (e.g: inserst,update,delete) then it take more time that of which have no indexes applied on table because the indexes also need updation so each index will be updated that take too much time. So you should apply indexes on columns or tables that we use it only for search purposes only. hope this will help u. thank u.
I've learned that views can be used to create custom "table views" (so to say) that aggregate related data from multiple tables.
My question is: what are the advantages of views? Specifically, let's say I have two tables:
event | eid, typeid, name
eventtype | typeid, max_team_members
Now I create a view:
eventdetails | event.eid, event.name, eventtype.max_team_members
| where event.typeid=eventtype.typeid
Now if I want to maximum number of members allowed in a team for some event, I could:
use the view
do a join query (or maybe a stored procedure).
What would be my advantages/disadvantages in each method?
Another query: if data in table events and eventtypes gets updated, is there any overhead involved in updating the data in the view (considering it caches resultant data)?
A view is not stored separately: when you query a view, the view is replaced with the definition of that view. So and changes to the data in the tables will show up immediately via the view.
In addition to the security feature pointed out earlier:
If you're writing a large number of queries that would perform that join, it factors out that SQL code. Like doing some operations in a function used in several places, it can make your code easier to read/write/debug.
It would also allow you to change how the join is performed in the future in one place. Perhaps a 1-to-many relationship could become a many-to-many relationship, introducing an extra table in the join. Or you may decide to denormalize and include all of the eventtype fields in each event record so that you don't have to join each time (trading space for query execution time).
You could further split tables later, changing it to a 3-way join, and other queries using the view wouldn't have to be rewritten.
You could add new columns to the table(s) and change the view to leave out the new columns so that some older queries using "select *" don't break when you change the table definitions.
You can restrict users to the view instead of the underlying table(s), thereby enhancing security.
Advantages of SQL Views
1). You can save a complex query(a query with join multiple tables) as view to reuse it in simple manners.
In other words, you can change your multi-line query into single-line query.
2). You can hide sensitive data by converting your query into view with new name and can give the access only required columns instead of giving the access of actual table.