当我想得到一个左连接SQL的计数时,它花了我很长时间, 我在1分钟后取消了查询,但没有得到结果。
我有两张桌子。 一个是客户,它看起来像:
----------------顾客---------------
`ID` int(11) NOT NULL AUTO_INCREMENT,
`drpc` int(10) DEFAULT NULL,
`VIN` varchar(60) COLLATE utf8_bin DEFAULT NULL,
`cph` varchar(30) COLLATE utf8_bin DEFAULT NULL,
//... another 60+ columns here
`invalid` int(1) DEFAULT NULL,
PRIMARY KEY (`ID`),
KEY `index_drpc_cph` (`drpc`,`cph`),
KEY `index_drpc_vin` (`drpc`,`VIN`),
KEY `index_drpc_invalid` (`drpc`,`invalid`),
KEY `index_cph` (`cph`)
另一个是修复,它看起来像:
------------- ----------------修复
`ID` int(11) NOT NULL AUTO_INCREMENT,
`drpc` int(10) NOT NULL,
`cph` varchar(10) DEFAULT NULL,
`czbh` varchar(15) DEFAULT NULL,
`gdh` varchar(12) DEFAULT NULL,
`kdrq` date DEFAULT NULL,
// ... another 20+ columns here
`invalid` int(1) DEFAULT '0',
PRIMARY KEY (`ID`),
KEY `gmrepair_cph` (`cph`),
KEY `gmrepair_czbh` (`czbh`),
KEY `gmrepair_gdh` (`gdh`),
KEY `gmrepair_drpc_kdrq` (`drpc`,`kdrq`),
KEY `index_drpc_invalid` (`drpc`,`invalid`),
KEY `index_drpc_cph` (`drpc`,`cph`)
两个表都有一个字段:'cph'。
最初的要求是:对于给定的 drpc ,获取客户中存在的 cph 数据,但修复中不存在强>
SELECT * FROM customer c LEFT JOIN
( SELECT cph FROM repair b WHERE b.drpc=77) r ON c.cph = r.cph
WHERE c.drpc = 76 AND r.cph IS NULL
以下是解释结果:
顺便说一句, 对于修复表中的drpc = 77,有大约20k的记录;
对于客户表中的drpc = 76,大约有6万条记录。
两个表的存储都是:InnoDB。
执行上面的sql大约需要3秒钟。
但是,当我想得到上面提到的sql的计数时,我需要很长时间。即使在60秒内也无法完成。
我不确定问题是什么。 能不能给我一些指示,万分感谢!
答案 0 :(得分:0)
查看计划的解释总是有帮助的。看起来drpc, cph
上的索引应该用于查询。
但是,如果您的基本查询有效,那么这可能会为您带来更好的效果。
select count(*)
from (SELECT *
FROM customer c LEFT JOIN
(SELECT distinct cph
FROM repair b
WHERE b.drpc=77
) r
ON c.cph = r.cph
WHERE c.drpc = 76 AND r.cph IS NULL
) t;
编辑:
您可以通过这样的方式强制执行计划:
select count(*)
from customer c
where c.drpc = 76 and
not exists (select 1 from repair r where r.drpc = 77 and r.cph = c.cph);
答案 1 :(得分:0)
尝试左外连接而不是左连接。
SELECT C.*
FROM Customer C
LEFT OUTER JOIN (SELECT cph from
FROM Repair WHERE drpc = 77)r ON C.cph = r.cph
WHERE C.drpc = 76 AND R.cph IS NULL
答案 2 :(得分:0)
我的理解是您提供的查询:
SELECT * FROM customer c LEFT JOIN
( SELECT cph FROM repair b WHERE b.drpc=77) r ON c.cph = r.cph
WHERE c.drpc = 76 AND r.cph IS NULL
应该与简单的左连接相同(这是计数版本):
select count(*) from customer c
where c.drpc = 76 and c.cph not in (
select cph from repair where drpc = 77
)
这第二个查询也花了太长时间吗?
答案 3 :(得分:0)
我不明白为什么其他人没有提及,但查询中的子查询不允许有效使用索引,实际上你在一个20k行的无索引表上保持连接。
对于查询,您需要2个索引: (drpc,cph)关于客户和(cph,drpc)的维修(记住订单,你还没有)。
然后你需要重写查询:
SELECT COUNT(*)
FROM customer c
LEFT JOIN repair r ON c.chp = r.chp AND r.drpc = 77
WHERE c.drpc = 76 AND r.chp IS NULL;
答案 4 :(得分:0)
我想我找到了真正的伎俩。
这是因为左连接字段cph
是varchar(10)
,导致左连接作业时非常慢。
我在两个表上创建了一个新列:hash_cph numberic(30,0)
,然后以这种方式将cph
转换为某些MD5
哈希数:
UPDATE customer SET hash_cph = CONV(RIGHT(MD5(cph),16),16,10)
。
所以我现在可以在新创建的列hash_cph
上应用左连接,它会快得多。
最终的SQL看起来像:
SELECT COUNT(*)
FROM customer c
LEFT JOIN repair r ON c.
{hash_cph {1}}
顺便说一句,我还在= r.hash_cph AND r.drpc = 32 WHERE c.drpc = 1
AND r.hash_cph IS NULL;
为两个表添加了索引。
感谢大家的帮助!!