I am wondering if anyone can explain to me when you would use a sub query and when you would use a join.
for example.
I have this query:
SELECT * from contacts where id in (select contactId from contactgrouplink where groupId = 1);
What would the benefit be of a join over this sub query?
Look at here well discussed
Subqueries vs joins
select * from contacts x, contactgrouplink y where x.id=y.contactId and y.groupId=1
Use EXPLAIN just before each of those query's... to see what query does!
Do an EXPLAIN, my rule of thumb is to try to get rid of DEPENDENT SUBQUERY since that means for each row in the outer SQL statement, a query is executed. Also, you can try to implement it as a join and see how many rows each version would examine and make the call from there.
In my knowledge, Sub-query is batter than join .
I'm also use Sub-query Becoz "Join" is Effecting performance. (According My-Sql Preference)
Related
I met the following MySQL code:
SELECT ServiceFee
FROM Shows
WHERE ID = (SELECT ShowID FROM Orders WHERE ID = ?)
It makes me wonder because the people who wrote this code usually use SQL joins. I would rewrite it
SELECT ServiceFee
FROM Shows
INNER JOIN Orders ON Shows.ID = Orders.ShowID
WHERE Orders.ID = ?
My question: Is there any reason why this code was written with a subquery and whether it is completely safe (producing the same result in all situations) to rewrite it with the join?
Are there any caveats?
"Is there any reason why this code was written with a subquery"
a very long time ago MySQL joins used to be slow
Without a context the two queries don't do the same. If Orders.ID is not unique, the first query might produce an error because the subquery can return multiple rows. If Orders.ID is unique (probably primary key) then there will not be any difference - neither in the result nor in the performance (with newer versions). So in this case it is just a question of preference. Usually i prefer joins. But in your example the subquery solution looks fine and readable. So i wouldn't rewrite it without a reason.
Nope, there are no caveats. As a matter of fact, the INNER JOIN query might run faster
There is a logical reason to prefer a Subquery over a Join:
Between Shows and Orders there's a 1-many relation, when you switch to a join you usually must add a DISTINCT to get rid of the duplicate rows returned.
In your case this is not needed, because you restrict to a single order, but when you remove the WHERE-condition or change it to return multiple rows you will notice that.
I am trying to select rows from a table which don't have a correspondence in the other table.
For this purpose, I'm currently using LEFT JOIN and WHERE joined_table.any_column IS NULL, but I don't think that's the fastest way.
SELECT * FROM main_table mt LEFT JOIN joined_table jt ON mt.foreign_id=jt.id WHERE jt.id IS NULL
This query works, but as I said, I'm looking for a faster alternative.
Your query is a standard query for this:
SELECT *
FROM main_table mt LEFT JOIN
joined_table jt
ON mt.foreign_id=jt.id
WHERE jt.id IS NULL;
You can try this as well:
SELECT mt.*
FROM main_table mt
WHERE not exists (select 1 from joined_table jt where mt.foreign_id = jt.id);
In some versions of MySQL, it might produce a better execution plan.
In my experience with MSSQL the syntax used (usually) produces the exact same query plan as the WHERE NOT EXISTS() syntax, however this is mysql, so I can't be sure about performance!!
That said, I'm a much bigger fan of using the WHERE NOT EXISTS() syntax for the following reasons :
it's easier to read. If you speak a bit of English anyone can deduce the meaning of the query
it's more foolproof, I've seen people test for NULL on a NULL-able field
it can't have side effects like 'doubled-records' due to the JOIN. If the referenced field is unique there is no problem, but again I've seen situations where people chose 'insufficient keys' causing the main-table to get multiple hits against the joined table... and off course they solved it again using DISTINCT (aarrgg!!! =)
As for performance, make sure to have a (unique) index on the referenced field(s) and if possible put a FK-relationship between both tables. Query-wise I doubt you can squeeze much more out of it.
My 2 cents.
The query that you are running is usually the fastest option, just make sure that you have an index forh both mt.foreign_id and jt.id.
You mentioned that this query is more complex, so it might be possible that the problem is in another part of the query. You should check the execution plan to see what is wrong and fix it.
I have followed the tutorial over at tizag for the MAX() mysql function and have written the query below, which does exactly what I need. The only trouble is I need to JOIN it to two more tables so I can work with all the rows I need.
$query = "SELECT idproducts, MAX(date) FROM results GROUP BY idproducts ORDER BY MAX(date) DESC";
I have this query below, which has the JOIN I need and works:
$query = ("SELECT *
FROM operators
JOIN products
ON operators.idoperators = products.idoperator JOIN results
ON products.idProducts = results.idproducts
ORDER BY drawndate DESC
LIMIT 20");
Could someone show me how to merge the top query with the JOIN element from my second query? I am new to php and mysql, this being my first adventure into a computer language I have read and tried real hard to get those two queries to work, but I am at a brick wall. I cannot work out how to add the JOIN element to the first query :(
Could some kind person take pity on a newb and help me?
Try this query.
SELECT
*
FROM
operators
JOIN products
ON operators.idoperators = products.idoperator
JOIN
(
SELECT
idproducts,
MAX(date)
FROM results
GROUP BY idproducts
) AS t
ON products.idproducts = t.idproducts
ORDER BY drawndate DESC
LIMIT 20
JOINs function somewhat independently of aggregation functions, they just change the intermediate result-set upon which the aggregate functions operate. I like to point to the way the MySQL documentation is written, which hints uses the term 'table_reference' in the SELECT syntax, and expands on what that means in JOIN syntax. Basically, any simple query which has a table specified can simply expand that table to a complete JOIN clause and the query will operate the same basic way, just with a modified intermediate result-set.
I say "intermediate result-set" to hint at the mindset which helped me understand JOINS and aggregation. Understanding the order in which MySQL builds your final result is critical to knowing how to reliably get the results you want. Generally, it starts by looking at the first row of the first table you specify after 'FROM', and decides if it might match by looking at 'WHERE' clauses. If it is not immediately discardable, it attempts to JOIN that row to the first JOIN specified, and repeats the "will this be discarded by WHERE?". This repeats for all JOINs, which either add rows to your results set, or remove them, or leaves just the one, as appropriate for your JOINs, WHEREs and data. This process builds what I am referring to when I say "intermediate result-set". Somewhere between starting and finishing your complete query, MySQL has in it's memory a potentially massive table-like structure of data which it built using the process I just described. Only then does it begin to aggregate (GROUP) the results according to your criteria.
So for your query, it depends on what specifically you are going for (not entirely clear in OP). If you simply want the MAX(date) from the second query, you can simply add that expression to the SELECT clause and then add an aggregation spec to the end:
SELECT *, MAX(date)
FROM operators
...
GROUP BY idproducts
ORDER BY ...
Alternatively, you can add the JOIN section of the second query to the first.
I have some problems with an (My)SQL query. In my DB I have two tables. One is called kfz_typen, the other kfz_temp2. I need to get all entries of the kfz_temp2 table, which ktyp (just an integer field) is not in the kfz_typen table.
SELECT * FROM kfz_temp2
WHERE kfz_temp2.KType NOT IN (SELECT DISTINCT kfz_typen.ktyp FROM kfz_typen)
In my opinion this query above should exactly do, what I want. But it doesn't! I just get an empty result back from my MySQL Server.
Without the "NOT" in the Query, I get the entries that are in both tables, so the matching does work.
So what's wrong with the Query above?
Would this work?
SELECT t2.* FROM kfz_temp2 t2
LEFT JOIN kfz_typen tn ON t2.KType = tn.ktyp
WHERE tn.ktyp IS NULL
You may need to group the result.
I'm unsure why the first query doesn't work, but I believe this does the same thing.
remove distinct then i hope it is helpful to you.
I am trying to retrieve the id's of the blogs from the users that sessionid follow:
SELECT * FROM articles
WHERE id_usuario IN (SELECT toid FROM follows WHERE fromid = '$id')
This gives me the expected result but the performance is pretty bad even with a small number of rows.
Would I be better served with a join?
You can quickly fix this by rewriting as:
SELECT * FROM articles WHERE id_usuario IN (SELECT toid FROM follows WHERE fromid = '$id' AND id_usuario = toid)
With your query, MySQL will try and materialize the outer query first (select all articles) and then filter based on the inner query, which is not efficient, unfortunately it's not smart enough right now to realise it should turn that subquery into a join.
You can give the optimizer the hint it needs though by referencing the outer table from the inner table on the condition you want to filter by, as I've done above.
Even for a simple query like that, it would be very surprising if a join offered better performance.
The one thing I can suggest is an index on id_usuario.
Also, to analyse what the engine does with your query, use Explain.