问题描述
我有一个非常复杂的 MySQL 查询,其中包括三次使用相同的子查询.MySQL 会实际运行子查询 3 次吗?(这是一个昂贵的.)如果是这样,我有没有办法告诉 MySQL 保存或缓存结果,所以它不会那样做?我可以将数据保存在一个大数组中,然后将其重新提供给 MySQL,但我不想像那样将其移出并移回数据库.
I have a very complex MySQL query that includes use of the same subquery three times. Will MySQL actually run the subquery three times? (It's an expensive one.) If so, is there a way for me to tell MySQL to save or cache the results so it won't do that? I could save the data in a large array then re-feed it to MySQL, but I'd rather not move it out and back into the database like that.
这是出现三次的子查询:
This is the subquery that appears three times:
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 here's an example of the full query in which the query appears:
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;
推荐答案
看看 EXPLAIN EXTENDED
怎么说.
如果它是 DEPENDENT SUBQUERY
或 UNCACHEABLE SUBQUERY
,那么每次使用时都会重新评估.
If it says DEPENDENT SUBQUERY
or UNCACHEABLE SUBQUERY
, then it will be reevaluated each time it's used.
如果子查询使用会话变量或者是相关子查询,就会发生这种情况.
This happens if the subquery uses session variables or is a correlated subquery.
如果没有,它很可能会被缓存.
If it doesn't, it most probably will be cached.
如果您的情况子查询不会被缓存,它将在每个 UNION
的集合中重新评估.
If your case the subquery will not be cached, it will be reevaluated in each UNION
'ed set.
不过,您的子查询似乎太复杂了.你为什么不直接使用:
You subquery, though, seems to be too complicated. Why don't you just use:
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)
上有一个索引,那么这个查询应该会很有效.
If you have an index on playlist_program_map (playlist_id)
, this query should work like a charm.
你能告诉我另外两件事吗:
Could you please tell me two more things:
playlist_program_map
中有多少行,DISTINCT playlist_id
值有多少?programs
中有多少行,DISTINCT submitter_id, feed_id
对有多少?
- How many rows are there in
playlist_program_map
and how manyDISTINCT playlist_id
values are there?- How many rows are there in
programs
and how manyDISTINCT submitter_id, feed_id
pairs are there?
- How many rows are there in
根据您的评论,我可以得出结论,每个 playlist
平均有 10 programs
,200 <每个 (submitter, feed)
对的 code>programs.这意味着 playlist_program_map
上的索引比 (submitter, feed)
上的索引更具选择性,并且 playlist_program_map
必须在连接中领先.
From your comment I can conclude that there are 10 programs
per playlist
in average, and 200 programs
per (submitter, feed)
pair. This means your index on playlist_program_map
is more selective than the one on (submitter, feed)
, and playlist_program_map
must be leading in the join.
鉴于您需要加入 2,000,000 中的 10 个程序,因此您的案例中的全文索引似乎也不是很有选择性.
The fulltext index in your case also doesn't seem to be very selective, given that you need to join 10 programs out of 2,000,000.
您最好尝试以下方法:
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'
,然后对所有三个表重复此操作.
, and repeat this for all three tables.
这篇关于在 MySQL 中缓存/重用子查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!