How to optimize IN constraint query? - mysql

Following is my query.
SELECT * FROM t1 WHERE t1.record_id IN (
SELECT t2.record_id FROM t2
INNER JOIN t3 ON CONCAT(t2.case_number,t2.courtfile_type) = CONCAT(t3.case_number,t3.courtfile_type))
It contain IN constraint which is taking lot of time to extract result from database.Database is huge obviously.
How can I optimize this query?

Try this:
USING JOIN
SELECT DISTINCT t1.*
FROM t1
INNER JOIN t2 ON t1.record_id = t2.record_id
INNER JOIN t3 ON t2.case_number = t3.case_number AND t2.courtfile_type = t3.courtfile_type
USING EXISTS
SELECT *
FROM t1
WHERE EXISTS (SELECT t2.record_id
FROM t2 INNER JOIN t3 ON t2.case_number = t3.case_number AND t2.courtfile_type = t3.courtfile_type
WHERE t1.record_id = t2.record_id )
Check the execution plan of the query using EXPLAIN keyword and do proper indexing on tables.

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

Multiple JOIN and OR in WHERE clause MySQL query optimization

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.

Error in query (1248): Every derived table must have its own alias INNER JOIN

I'd like to use INNER JOIN on 2 tables, but when I try either of the below statements, I get
Error in query (1248): Every derived table must have its own alias
SELECT DISTINCT(t2.col)
FROM tab2 as t2
INNER JOIN (
SELECT DISTINCT(t1.col)
FROM tab1 as t1
WHERE t1.id>678 AND t1.id<5248
) ON t2.col=t1.col
WHERE t2.id>10 AND t2.id<3770
SELECT DISTINCT(col)
FROM tab2 as t2
INNER JOIN (
SELECT DISTINCT(col)
FROM tab1 as t1
WHERE t1.id>678 AND t1.id<5248
) ON t2.col=t1.col
WHERE t2.id>10 AND t2.id<3770
What's the problem?
You nee to add an alias to your join table:
SELECT DISTINCT(t2.col) FROM tab2 as t2 INNER JOIN (SELECT DISTINCT(t1.col) FROM tab1 as t1 WHERE t1.id>678 AND t1.id<5248) as t3 ON t2.col=t3.col WHERE t2.id>10 AND t2.id<3770
You need to provide an alias for the join:
SELECT DISTINCT(t2.col)
FROM tab2 as t2
INNER JOIN (
SELECT DISTINCT(t1.col)
FROM tab1 as t1
WHERE t1.id>678 AND t1.id<5248
) as myJoinName ON t2.col=myJoinName.col
WHERE t2.id>10 AND t2.id<3770
Repeat for the second query. You also need to change the way you join to use this alias as t1 will be out of scope of the join condition.
Error in query (1248): Every derived table must have its own alias
This error is self-explanatory and is being caused by your subqueries not having an alias assigned to them. In fact, every derived table needs an alias even if you don't use it. Try the following queries:
SELECT DISTINCT t2.col
FROM tab2 as t2
INNER JOIN
(
SELECT DISTINCT t.col
FROM tab1 t
WHERE t.id > 678 AND t.id < 5248
) t1
ON t2.col = t1.col
WHERE t2.id > 10 AND t2.id < 3770
SELECT DISTINCT col
FROM tab2 as t2
INNER JOIN
(
SELECT DISTINCT col
FROM tab1 as t
WHERE t.id > 678 AND t.id < 5248
) t1
ON t2.col = t1.col
WHERE t2.id > 10 AND t2.id < 3770

Store mysql subquery in a variable

Is is possible to store a mysql subquery somehow, if it will be used again as a subquery? Presumably this would produce cleaner code as well as save parsing overheads.
For example in the following outer join
SELECT * FROM t1
LEFT JOIN (SELECT * FROM t2 WHERE t2.foo=='bar') ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN (SELECT * FROM t2 WHERE t2.foo=='bar') ON t1.id = t2.id
It would be nice not to repeat (SELECT * FROM t2 WHERE t2.foo=='bar').
No, you can't. If MySQL had CTE (Common Table Expressions), you could use this:
WITH tmp AS
(SELECT * FROM t2 WHERE t2.foo = 'bar')
SELECT * FROM t1
LEFT JOIN tmp ON t1.id = tmp.id
UNION
SELECT * FROM t1
RIGHT JOIN tmp ON t1.id = tmp.id
If MySQL had FULL JOIN (which alas, it hasn't either!), you could use this:
SELECT * FROM t1
FULL JOIN (SELECT * FROM t2 WHERE t2.foo = 'bar') tmp
ON t1.id = tmp.id
Of course do it like this
SET #condition := (SELECT * FROM t2 WHERE t2.foo=='bar');
SELECT * FROM t1
LEFT JOIN (#condition) ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN (#condition) ON t1.id = t2.id

Select in where clause, access to current parent select columns

I have a query which contains a select statement in it's where clause. My question is now, how can I access the parent's select's data.
Example:
select * from TABLE_1 as t1 INNER JOIN TABLE_2 as t2
where (... and ...) OR
(not exists(select * from TABLE_3 as t3
inner join TABLE_1 ON t3.t1_id = t1.id
The last line is where the error occurs: t1.id is not a column.
How can I access the current value from the table t1?
I'm using MySql 5.1
SELECT
*
FROM
TABLE_1 as t1
INNER JOIN TABLE_2 as t2 ON
t2.PK = t1.FK --Whatever your keys are
WHERE
(... and ...)
OR
(
NOT EXISTS (select * from TABLE_3 as t3 WHERE t3.t1_id = t1.id)
)
First of all, you need to declare what you will JOIN TABLE_2 on TABLE_1.
SELECT *
FROM TABLE_1 AS t1
INNER JOIN TABLE_2 AS t2 ON t2.t1_id = t1.id
t1.id = t2.t1_id is just an example, you will need to decide which columns you wish you join on. Then in your WHERE clause, you do not need to INNER JOIN on TABLE_1 again as you are already selecting from it.
SELECT *
FROM TABLE_1 AS t1
INNER JOIN TABLE_2 AS t2 ON t2.t1_id = t1.id
WHERE (... AND ...) OR
(
NOT EXISTS
(
SELECT *
FROM TABLE_3 AS t3
WHERE t3.t1_id = t1.id
)
)