缓存/重用MySQL中的子查询

时间:2009-03-18 16:10:31

标签: mysql subquery

我有一个非常复杂的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;

2 个答案:

答案 0 :(得分:8)

查看EXPLAIN EXTENDED说的内容。

如果显示DEPENDENT SUBQUERYUNCACHEABLE 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)上有索引,则此查询应该像魅力一样。

请你告诉我另外两件事:

  1. playlist_program_map中有多少行以及有多少DISTINCT playlist_id个值?
    • programs中有多少行以及有多少DISTINCT submitter_id, feed_id对?
  2. 根据您的评论,我可以得出结论:平均每programs 10 playlist,每{{strong> 200 programs {一对。这意味着(submitter, feed)上的索引比playlist_program_map上的索引更具选择性,(submitter, feed)必须在联接中领先。

    鉴于你需要加入 2,000,000 之外的 10 程序,你的案例中的全文索引似乎也不是很有选择性。

    您最好尝试以下方法:

    playlist_program_map

    ,并对所有三个表重复此操作。

答案 1 :(得分:0)

无论出于何种原因,带有子选择的mysql IN子句运行速度非常慢。最好使用join。您的子查询变为:

程序中的SELECT id IN INNER JOIN程序P2 ON P1.id = P2.id INNER JOIN playlist_program_map PMAP ON P2.id = PMAP.program_id WHERE P1.submitter_id = 32 AND P2.feed_id = 2478 AND PMAP.playlist_id = 181

它运行得更快。