我有一个非常复杂的MySQL查询,包括使用相同的子查询三次.MySQL实际上会运行子查询三次吗?(这是一个昂贵的.)如果是这样,有没有办法告诉MySQL保存或缓存结果,所以它不会这样做?我可以将数据保存在一个大型数组中,然后将其重新提供给MySQL,但我宁愿不将它移出并重新进入数据库.
这是三次出现的子查询:
SELECT id FROM programs WHERE submitter_id=32 AND id in ( SELECT id FROM programs WHERE feed_id=2478 AND id in ( SELECT program_id FROM playlist_program_map WHERE playlist_id=181)))
这是查询出现的完整查询的示例:
SELECT object_id, programs.created AS created, MATCH(text) AGAINST ('excellent ' IN BOOLEAN MODE) AS relevance FROM comments_programs USE INDEX (text) LEFT JOIN programs ON programs.id=object_id WHERE object_id IN ( SELECT id FROM programs WHERE 1 AND id IN ( SELECT id FROM programs WHERE submitter_id=32 AND id in ( SELECT id FROM programs WHERE feed_id=2478 AND id in ( SELECT program_id FROM playlist_program_map WHERE playlist_id=181)))) AND MATCH(text) AGAINST ('excellent ' IN BOOLEAN MODE)>0) UNION ( SELECT object_id, programs.created AS created, MATCH(text) AGAINST ('excellent ' IN BOOLEAN MODE) AS relevance FROM descriptions_programs USE INDEX (text) LEFT JOIN programs ON programs.id=object_id WHERE object_id IN ( SELECT id FROM programs WHERE 1 AND id IN ( SELECT id FROM programs WHERE submitter_id=32 AND id in ( SELECT id FROM programs WHERE feed_id=2478 AND id in ( SELECT program_id FROM playlist_program_map WHERE playlist_id=181)))) AND MATCH(text) AGAINST ('excellent ' IN BOOLEAN MODE)>0 AND current=1 ) UNION ( SELECT object_id, programs.created AS created, MATCH(text) AGAINST ('excellent ' IN BOOLEAN MODE) AS relevance FROM titles_programs USE INDEX (text) LEFT JOIN programs ON programs.id=object_id WHERE object_id IN ( SELECT id FROM programs WHERE 1 AND id IN ( SELECT id FROM programs WHERE submitter_id=32 AND id in ( SELECT id FROM programs WHERE feed_id=2478 AND id in ( SELECT program_id FROM playlist_program_map WHERE playlist_id=181)))) AND MATCH(text) AGAINST ('excellent ' IN BOOLEAN MODE)>0 AND current=1;
Quassnoi.. 8
看看EXPLAIN EXTENDED
说了什么.
如果它说DEPENDENT SUBQUERY
或UNCACHEABLE SUBQUERY
,那么每次使用它时都会重新评估.
如果子查询使用会话变量或是相关子查询,则会发生这种情况.
如果没有,它很可能会被缓存.
如果你的情况不会缓存子查询,它将在每个UNION
'ed集中重新评估.
但是,你的子查询似乎太复杂了.你为什么不用它:
SELECT id FROM playlist_program_map ppm, programs p WHERE ppm.playlist_id = 181 AND p.id = ppm.program_id AND submitter_id = 32 AND feed_id = 2478
如果您有索引playlist_program_map (playlist_id)
,则此查询应该像魅力一样工作.
你能告诉我另外两件事吗:
有多少行,有playlist_program_map
多少个DISTINCT playlist_id
值?
有多少行,有programs
多少DISTINCT submitter_id, feed_id
对?
根据您的评论,我可以得出结论,平均每个10 programs
个playlist
,每对200 programs
个(submitter, feed)
.这意味着您的索引playlist_program_map
更有选择性(submitter, feed)
,并且playlist_program_map
必须在连接中处于领先地位.
您的案例中的全文索引似乎也不是非常有选择性,因为您需要加入2,000,000个中的10个程序.
您最好尝试以下方法:
SELECT object_id, programs.created AS created FROM playlist_program_map ppm, programs p, comments_programs cp WHERE ppm.playlist_id = 181 AND p.id = ppm.program_id AND p.submitter_id = 32 AND p.feed_id = 2478 AND cp.object_id = p.id AND cp.text REGEXP 'excellent'
,并对所有三个表重复此操作.
看看EXPLAIN EXTENDED
说了什么.
如果它说DEPENDENT SUBQUERY
或UNCACHEABLE SUBQUERY
,那么每次使用它时都会重新评估.
如果子查询使用会话变量或是相关子查询,则会发生这种情况.
如果没有,它很可能会被缓存.
如果你的情况不会缓存子查询,它将在每个UNION
'ed集中重新评估.
但是,你的子查询似乎太复杂了.你为什么不用它:
SELECT id FROM playlist_program_map ppm, programs p WHERE ppm.playlist_id = 181 AND p.id = ppm.program_id AND submitter_id = 32 AND feed_id = 2478
如果您有索引playlist_program_map (playlist_id)
,则此查询应该像魅力一样工作.
你能告诉我另外两件事吗:
有多少行,有playlist_program_map
多少个DISTINCT playlist_id
值?
有多少行,有programs
多少DISTINCT submitter_id, feed_id
对?
根据您的评论,我可以得出结论,平均每个10 programs
个playlist
,每对200 programs
个(submitter, feed)
.这意味着您的索引playlist_program_map
更有选择性(submitter, feed)
,并且playlist_program_map
必须在连接中处于领先地位.
您的案例中的全文索引似乎也不是非常有选择性,因为您需要加入2,000,000个中的10个程序.
您最好尝试以下方法:
SELECT object_id, programs.created AS created FROM playlist_program_map ppm, programs p, comments_programs cp WHERE ppm.playlist_id = 181 AND p.id = ppm.program_id AND p.submitter_id = 32 AND p.feed_id = 2478 AND cp.object_id = p.id AND cp.text REGEXP 'excellent'
,并对所有三个表重复此操作.