简体   繁体   中英

How to optimize this SQL statement?

I need to select from a list of tables(list1,list2,list3,...) based on the select result from one table(tableA). How can I reuse the select result from that one table(tableA)?

my solution is

select * from list1 where list1.id in(select id from tableA where ...)
select * from list2 where list2.id in(select id from tableA where ...)
select * from list3 where list3.id in(select id from tableA where ...)
...

In my solution, select id from tableA where ... is executed by 3 times, it may take a lot of time, not efficient. In my imagination, select id from tableA where ... should only be executed once.

Can anyone help me?

Two things to note. First, in some versions of MySQL, the exists version is more efficient:

select *
from list1
where exists (select 1 from tableA a where a.id = list1.id and (...))
. . .

Second, you want to have the right indexes on tableA to optimize the query. Basically, the right index is a composite index where the first key is id and the columns in the where clause follow.

The best way to order the columns in the index depends on the where conditions. If the conditions are all equality conditions connected by and , then the ordering doesn't matter.

You could use a temporary table to store the results of the subquery in memory and replace your subquery with a simple IN (select id from tmptable) . I assume your original subquery is slightly more complicated and maybe contains complex WHERE conditions:

CREATE TEMPORARY TABLE tmptable 
AS SELECT id FROM tableA WHERE complex = condition AND more = conditions;

SELECT * FROM list1 l WHERE l.id IN (SELECT id FROM tmptable)
SELECT * FROM list2 l WHERE l.id IN (SELECT id FROM tmptable)
...

As a result, the complex query is only executed once, the result is stored in-memory and is being re-used by the following queries.

If all 3 SELECTs return compatible results you might try combining them using UNION ALL:

select *
FROM
 (
   select * from list1
   UNION ALL
   select * from list2
   UNION ALL
   select * from list3
 ) as dt
 where id in (select id from tableA where ...)

But I doubt that MySQL's optimizer can handle this well...

There isn't a more efficient way to do this. There's no getting around the fundamental fact that you have to compare two lists with each other n times, where n is the number of list tables you have.

This is sort of like comtemplating the following set of additions:

a + 5 = ?
b + 5 = ?
c + 5 = ?
d + 5 = ?

Hey isn't there some way to optimise this? After all I'm just adding 5 every time!

No, not really. In this example you could write a function that added 5 to something and that would reduce the amount of code and be better from a DRY perspective. But that wouldn't "optimise" it in terms of reducing execution time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM