如果我有以下两个表:
我可以运行以下查询来从表a中选择行,其中表b condition1为1
SELECT a.id FROM a WHERE EXISTS (SELECT 1 FROM b WHERE b.id_table_a=a.id && condition1=1 LIMIT 1) ORDER BY a.column1 LIMIT 50
在两个表中有几亿行,这个查询非常慢。如果我这样做:
SELECT a.id FROM a INNER JOIN b ON a.id=b.id_table_a && b.condition1=1 ORDER BY a.column1 LIMIT 50
这几乎是即时的,但如果表b中有多个匹配的行匹配id_table_a,则返回重复项。如果我执行SELECT DISTINCT或GROUP BY a.id来删除重复项,则查询变得非常慢。
这是一个显示示例查询的SQLFiddle:http://sqlfiddle.com/#!9/35eb9e/10
在这种情况下,有没有办法快速建立没有重复的连接?
*编辑显示INNER而不是LEFT加入没有太大的区别
*编辑显示加入的移动条件没有太大的区别
*编辑添加LIMIT
*已编辑添加ORDER BY
答案 0 :(得分:1)
您可以尝试使用内部联接和不同的
SELECT distinct a.id
FROM a INNER JOIN b ON a.id=b.id_table_a AND b.condition1=1
但在select *上使用distinct,请确保在这种情况下不要使用返回错误结果的不同ID
SELECT distinct col1, col2, col3 ....
FROM a INNER JOIN b ON a.id=b.id_table_a AND b.condition1=1
您还可以使用condtition1添加复合索引,例如:key(id,condition1)
如果可以,你也可以执行
ANALYZE TABLE table_name;
在桌子上..
另一种技术是尝试恢复潜在客户表
SELECT distinct a.id
FROM b INNER JOIN a ON a.id=b.id_table_a AND b.condition1=1
使用最具选择性的表来引导查询
使用这个似乎与使用索引http://sqlfiddle.com/#!9/35eb9e/15(最后添加使用where)
不同# USING DISTINCT TO REMOVE DUPLICATES without col and order
EXPLAIN
SELECT DISTINCT a.id
FROM a
INNER JOIN b ON a.id=b.id_table_a AND b.condition1=1
;
答案 1 :(得分:1)
看起来我找到了答案。
SELECT a.id FROM a
INNER JOIN b ON
b.id_table_a=a.id &&
b.condition1=1 &&
b.condition2=(select b.condition2 from b WHERE b.id_table_a=a.id && b.condition1=1 LIMIT 1)
ORDER BY a.column1
LIMIT 5;
我不知道这是否存在缺陷,如果有,请告诉我。如果有人有办法以某种方式压缩这个,我很乐意接受你的回答。
答案 2 :(得分:0)
SELECT id FROM a INNER JOIN b ON a.id=b.id_table_a AND b.condition1=1
将条件带入连接的ON
子句,这样可以使用表b的索引进行过滤。同时使用INNER JOIN
而不是LEFT JOIN
然后你应该将较少的结果分组。
答案 3 :(得分:0)
在处理重复数据删除和限制的查询中包装快速版本:
SELECT DISTINCT * FROM (
SELECT a.id
FROM a
JOIN b ON a.id = b.id_table_a && b.condition1 = 1
) x
ORDER BY column1
LIMIT 50
我们知道内部查询很快。重复删除和排序必须在某处进行。这种情况发生在可能的最小行集上。
请参阅SQLFiddle。
选项2:
尝试以下方法:
按如下方式创建索引:
create index a_id_column1 on a(id, column1)
create index b_id_table_a_condition1 on b(a_table_a, condition1)
这些是覆盖索引 - 包含查询所需的所有列的索引,这反过来意味着对数据的仅索引访问可以实现结果。
然后试试这个:
SELECT * FROM (
SELECT a.id, MIN(a.column1) column1
FROM a
JOIN b ON a.id = b.id_table_a
AND b.condition1 = 1
GROUP BY a.id) x
ORDER BY column1
LIMIT 50
答案 4 :(得分:0)
在子选择中使用快速查询并删除外部选择中的重复项:
SELECT DISTINCT sub.id
FROM (
SELECT a.id
FROM a
INNER JOIN b ON a.id=b.id_table_a && b.condition1=1
WHERE b.id_table_a > :offset
ORDER BY a.column1
LIMIT 50
) sub
由于删除重复项,您可能会少于50行。只需重复查询,直到获得足够的行。从:offset = 0
开始。在以下查询中,将最后一个结果中的最后一个ID用作:offset
。
如果您了解统计信息,则还可以使用两个限制。内部查询中的限制应足够高,以返回50个不同的行,其概率足够高。
SELECT DISTINCT sub.id
FROM (
SELECT a.id
FROM a
INNER JOIN b ON a.id=b.id_table_a && b.condition1=1
ORDER BY a.column1
LIMIT 1000
) sub
LIMIT 50
例如:如果每个ID平均有10个重复项,则内部查询中的LIMIT 1000
将返回平均100个不同的行。你不太可能得到少于50行。
如果condition2
列是布尔值,您知道最多可以有两个重复项。在这种情况下,内部查询中的LIMIT 100
就足够了。