0

当我想得到一个左连接SQL的计数时,我花了很长时间,1分钟后我取消了查询,没有得到结果。

我有两张桌子。一个是customer,它看起来像:

- - - - - - - - 顾客 - - - - - - - -

  `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`)

另一个是repair,它看起来像:

- - - - - - -修理 - - - - - - - -

`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,获取那些存在于customer中但不存在于repair中的数据cph

我的 sql 语句如下所示:

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 

这是解释结果:

在此处输入图像描述

BTW,对于修复表中的drpc = 77,大约有20k条记录;

对于客户表中的 drpc = 76,大约有 60k 条记录。

两个表的存储都是:InnoDB。

执行上面的sql大约需要3秒。

但是,当我想得到上面提到的 sql 的计数时,我需要很长时间。它甚至无法在 60 秒内完成。

我不确定问题是什么。能否请您给我一些指点,谢谢一百万!

4

5 回答 5

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;
于 2013-08-29T06:33:00.347 回答
0

我想我找到了真正的诀窍。

这是因为 left join 归档cph,这是一个varchar(10),导致在做 left join 工作时非常非常慢。

我创建了一个新列: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= r.hash_cph AND r.drpc = 32 WHERE c.drpc = 1 AND r.hash_cph IS NULL;

drpc and hash_cph顺便说一句,我还为两个表添加了索引。

感谢大家的帮助!!

于 2013-09-17T03:54:39.647 回答
0

It always helps to look at the explain for the plans. It looks like the index on drpc, cph should be used for the query.

However, if your base query works, perhaps this will give you better performance.

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;

EDIT:

You may be able to force the execution plan by phrasing the query like this:

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);
于 2013-08-27T02:21:48.523 回答
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
于 2013-08-27T02:26:15.483 回答
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
)

这第二个查询是否也需要太长时间?

于 2013-08-27T02:32:23.143 回答