Multiple JOIN and OR in WHERE clause MySQL query optimization - mysql

I'm trying to optimize a query similar to this one:
SELECT * FROM table1 t1 INNER JOIN table2 t2 ON t1.t2_id = t2.id
LEFT OUTER JOIN table3 t3 ON t1.t3_id = t3.id
LEFT OUTER JOIN table4 t4 ON t3.t4_id = t4.id
LEFT OUTER JOIN table5 t5 ON t3.t5_id = t5.id
LEFT OUTER JOIN table6 t6 ON t1.t6_id = t6.id
WHERE (t1.attribute1 = ? OR t2.attribute2 = ?)
AND t1.active = 1
AND t1.status <> 10
what I saw in the logs is that what takes most is the OR in the WHERE clause (with the OR the query takes ~1s for its execution, while without it it takes around ~400 ms with the data that I've sampled from the DB).
I'm looking for alternatives to get the same results without taking much time (also, performance decreases if many queries are executed concurrently).
I've tried replacing the OR with an union subquery with a join between t1 and t2 (I'm working with MySQL 5.7):
SELECT * FROM (SELECT * FROM table1 t1 INNER JOIN table2 t2 ON t1.t2_id = t2.id
WHERE t1.attribute1 = ?
UNION
SELECT * FROM table1 t1 INNER JOIN table2 t2 ON t1.t2_id = t2.id
WHERE t2.attribute2 = ?
) AS joined
LEFT OUTER JOIN table3 t3 ON joined.t3_id = t3.id
LEFT OUTER JOIN table4 t4 ON t3.t4_id = t4.id
LEFT OUTER JOIN table5 t5 ON t3.t5_id = t5.id
LEFT OUTER JOIN table6 t6 ON joined.t6_id = t6.id
WHERE joined.active = 1
AND joined.status <> 10
But I'd like to know if there is a better approach for optimizing the query.
EDIT: active, status, attribute1 and attribute2 are indexed as well as the ids.

The following index can increase the performance of the first query, as long as your are not selecting too many rows (ideally less than 1000 rows):
create index ix1 on table1 (attribute1, active, status, t2_id);
Add this index. If it's still slow, add the execution plan to your question.

Related

mySQL group two INNER JOINs

I basically want to join the result of two INNER JOINs.
On this scheme I want to get the three arrows results combined.
I've tried INNER / LEFT combinations but it doesn't do the trick.
I think a nested request could be the solution but how ?
Thanks
The answer was actually simple : UNION
SELECT t1.*
FROM
(SELECT t1.*
FROM table1 t1 JOIN table2 t2 ON t2.id = i.client_id
UNION
SELECT t1.*
FROM t1 t1 JOIN table3 t3 ON t1.id = t3.client_id) as q1
;
I'd use logic to express the condition T1.id exists in T2 or T3 more directly, and certainly avoid use of DISTINCT or UNION.
Options could be to use EXISTS directly (As this is immure to the possibility of duplication cause by 1:many joins)...
SELECT
t1.*
FROM
table1 t1
WHERE
EXISTS (SELECT * FROM table2 t2 WHERE t2.t1_id = t1.id)
OR
EXISTS (SELECT * FROM table3 t3 WHERE t3.t1_id = t1.id)
Or to LEFT JOIN twice and then exclude unwanted rows. (This assumes that the joins are never 1:many, which would introduce duplication, and the unwanted need for a DISTINCT.)
SELECT
t1.*
FROM
table1 t1
LEFT JOIN
table2 t2
ON t1.id = t2.t1_id
LEFT JOIN
table3 t3
ON t1.id = t3.t1_id
WHERE
t2.t1_id IS NOT NULL
OR
t3.t1_id IS NOT NULL

UNION in WHERE clause of update subquery

Are there any reasons why UNIONs shouldn't be used in the WHERE clause of update subqueries? Or for that matter, even normal select subqueries?
Is there a better way such a query to eliminate the UNION?
Note that for my case, the UNION will result in a fairly small number of records.
UPDATE mytable
set mytable.bla='xxx'
WHERE id IN (
SELECT id
FROM t1
INNER JOIN t2 ON t2.t1_id=t1.id
LEFT OUTER JOIN t3 ON t3.t1_id=t2.id
WHERE t2.id IN (1,2,3) AND t3.id IS NULL
UNION
SELECT id FROM t4
INNER JOIN t5 ON t5.id=t4.t5_id
LEFT OUTER JOIN t6 ON t6.t5_id=t5.id
WHERE t5.parent_id IN (1,2,3) AND t6.id IS NULL
);
Switching it to a join:-
UPDATE mytable
INNER JOIN
(
SELECT id
FROM t1
INNER JOIN t2 ON t2.t1_id=t1.id
LEFT OUTER JOIN t3 ON t3.t1_id=t2.id
WHERE t2.id IN (1,2,3)
AND t3.id IS NULL
UNION
SELECT id
FROM t4
INNER JOIN t5 ON t5.id=t4.t5_id
LEFT OUTER JOIN t6 ON t6.t5_id=t5.id
WHERE t5.parent_id IN (1,2,3)
AND t6.id IS NULL
) sub0
ON mytable.id = sub0.id
SET mytable.bla='xxx'

Inner Join on three tables takes too long in mysql

I am querying 3 tables in mysql.
SELECT t1.some_col
,t2.some_col
,t3.some_col
FROM t1, t2, t3
WHERE t1.a_col = t2.a_col AND t2.a_col = t3.a_col
AND a filter on t1
AND a filter on t2
AND a filter on t3
Which is taking too much time. (Not even giving results after 10 mins). Any optimization suggesation would be great.
Table t1 (.3m rows), t2 (1.1m) and t3 (258 rows). No tables has indexes, even I am not allowed to create one.
Edit (btw, huh?):
SELECT t2.parent_customerID ,
aggregate(t1.some_columns)
FROM t1, t2, t3
WHERE t1.customerID = t2.customerID
AND t2.parent_customerID = t3.parent_customerID
AND t1_where_entity_type_customer
AND t2_parent_customer_belonging_a_region_filter
AND t3_a_flag_check_on_parent_customer
GROUP BY t2.parent_customer
Try this approach.
SELECT t1.some_col
,t2.some_col
,t3.some_col
FROM t1
INNER JOIN t2 ON t1.a_col = t2.a_col
INNER JOIN t3 ON t2.a_col = t3.a_col
WHERE a filter on t1 AND a filter on t2 AND a filter on t3
Try to change the order of the where conditions.
SELECT t1.some_col
,t2.some_col
,t3.some_col
FROM t1, t2, t3
WHERE a filter on t1
AND a filter on t2
AND a filter on t3
AND t1.a_col = t2.a_col
AND t2.a_col = t3.a_col;

I Only Know 2 Tables in Left Join SQL Query. What if I have 3 or More Tables?

I'm creating sql command where the date stored in different table with foreign key of borrowers_id. I can execute and output left join of 2 tables but what if I have 3 or more tables fetching the datas of my foreign key.
Here's my SQL command,
SELECT borrowers.firstname,
borrowers.middlename,
borrowers.lastname,
borrowers.home_address,
borrowers.date_of_birth,
borrowers.age,
borrowers.residential_status,
borrowers.status,
borrowers.date_added,
borrowersp.spouse_name,
borrowersp.date_of_birth,
borrowersp.age
FROM tblborrowers as borrowers LEFT JOIN tblborrowerspouse as borrowersp
ON borrowers.borrowers_id = borrowersp.borrowers_id
WHERE borrowers.borrowers_id=23432413;
You can add more tables by continuing to join:
FROM tblborrowers as borrowers LEFT JOIN tblborrowerspouse as borrowersp
ON borrowers.borrowers_id = borrowersp.borrowers_id
LEFT JOIN tblborrowerskid as kid
ON borrowers.borrowers_id = kid.parent_id
WHERE borrowers.borrowers_id=23432413;
You can add as many as you'd need.
Lets say you have tables : t1 ,t2 and t3 ..Left Joining :
SELECT t2.id, t1.id AS Expr1
FROM t3 LEFT JOIN
t1 ON t3.id = t1.id LEFT JOIN
t2 ON t1.id = t2.id
We can also write the above query with left outer join :
SELECT t2.id, t1.id AS Expr1
FROM t3 LEFT OUTER JOIN
t1 ON t3.id = t1.id LEFT OUTER JOIN
t2 ON t1.id = t2.id
For 5 tables ..t1,t2,t3,t4 and t5 :
SELECT t2.id, t1.id AS Expr1, t5.id AS Expr2, t4.id AS Expr3
FROM t5 LEFT OUTER JOIN
t1 ON t5.id = t1.id LEFT OUTER JOIN
t4 ON t1.id = t4.id LEFT OUTER JOIN
t3 ON t1.id = t3.id LEFT OUTER JOIN
t2 ON t1.id = t2.id
Please have a look at this SO post :
What's the difference between INNER JOIN, LEFT JOIN, RIGHT JOIN and FULL JOIN?

Transforming queries: right joins to left joins

Suppose I have following tables: T1,T2 and T3.
How could I rephrase the following query using only left joins.
Select *
From T1
Right join T2 On T1.FK2=T2.PK
Right join T3 On T1.FK3=T3.PK
Following attempt is not correct:
Select *
From T2
Left join T1 On T1.FK2=T2.PK
Left join T3 On T1.FK3=T3.PK
T3 is On the wrong Side of the join. Is the following possible:
Select *
From T2
Left join T3 On T1.FK3=T3.PK
Left join T1 On T1.FK2=T2.PK
I can't Find a way to put both tables 2 and 3 On the left Side of 1 and use the correspondent fields to join all tables? The last query uses fields of table 1 before this table is mentioned in the query.
Or something like this?
Select *
From T2
Left join (
T3 left join T1
On T1.FK3=T3.PK)
On T1.FK2=T2.PK
Apparently brackets can help to order your joins. I wonder if this is really documented, i've found Nothing at first glance in the mysql docs.
Following query is correct and does not have any subqueries:
Select T1.Id Ida, t2.id idb, T3.id idc FROM T3
LEFT JOIN
(T2
LEFT JOIN T1 ON (T1.ID = T2.ID))
ON (T1.ID= T3.ID);
You need to use a subquery to first join t1 with t2 and then join the result with t3:
SELECT T.ID1 ID1, T.ID2 ID2, T3.ID ID3 FROM T3
LEFT JOIN
(SELECT T1.ID ID1, T2.ID ID2 FROM T2
LEFT JOIN T1 ON (T1.ID = T2.ID)) T
ON (T.ID1 = T3.ID);
SQL Fiddle
The first way is just to reverse the order that the tables are mentioned:
Select *
from t3 left outer join
t2
on T1.FK3 = T3.PK left outer join
t1
on T1.FK2 = T2.PK
But this won't work, because the first condition is on t1 and not t2. And t2 hasn't yet been defined.
When working with chains of tables in left or right outer joins, only the first (or last) tables are important, because they "drive" the query. "Drive" in the sense that they provide all the values even when there are no matches. So, the following should do what you want:
Select *
from t3 left outer join
t1
on T1.FK3 = T3.PK left outer join
t2
on T1.FK2 = T2.PK;