3

我对“IS NULL” MySQL 检查感到怀疑。我有这两个查询。第一个运行大约 300 秒。第二个跑不到1秒!

慢查询:

SELECT count(distinct(u.id))
FROM ips_usuario AS u 
JOIN ips_fatura AS f
    ON ((u.id = f.ips_usuario_id) OR
       (u.ips_usuario_id_titular IS NOT NULL AND
        u.ips_usuario_id_titular = f.ips_usuario_id));

在此处输入图像描述

快速查询:

SELECT count(distinct(u.id))
FROM ips_usuario AS u 
JOIN ips_fatura AS f
    ON ((u.id = f.ips_usuario_id) OR
       (u.ips_usuario_id_titular = f.ips_usuario_id));

在此处输入图像描述

所有连接条件都使用外键索引列。表 ips_usuario 有大约 20.000 条记录,而表 ips_fatura 有大约 500.000 条记录。

4

1 回答 1

1

我很惊讶两者都很快。我建议将它们替换为exists

SELECT COUNT(*)
FROM ips_usuario u  
WHERE EXISTS (SELECT 1 FROM ips_fatura f WHERE u.id = f.ips_usuario_id) OR
      EXISTS (SELECT 1 FROM ips_fatura f WHERE u.ips_usuario_id_titular = f.ips_usuario_id);

对于第二个:

SELECT COUNT(*)
FROM ips_usuario u  
WHERE EXISTS (SELECT 1 FROM ips_fatura f WHERE u.id = f.ips_usuario_id) OR
      (u.ips_usuario_id_titular IS NOT NULL AND
       EXISTS (SELECT 1 FROM ips_fatura f WHERE u.ips_usuario_id_titular = f.ips_usuario_id)
      )

对于这两个,您需要两个索引: ips_fatura(ips_usuario_id)ips_fatura(ips_usuario_id_titular). 您可以检查说明以确保EXISTS正在使用索引。如果没有,较新版本的 MySQL 使用以下索引IN

SELECT COUNT(*)
FROM ips_usuario u  
WHERE u.id IN (SELECT f.ips_usuario_id FROM ips_fatura f) OR
      u.ips_usuario_id_titular IN (SELECT f.ips_usuario_id FROM ips_fatura f);

在任何一种情况下(EXISTSIN),目标都是进行“半连接”。也就是说,只对第一行进行匹配而不是所有匹配。这是一个重要的效率,因为它允许查询避免重复删除。

我推测问题在于优化or- 通常这会导致JOIN算法效率低下。但是,也许 MySQL 在您的第一种情况下很聪明。但是添加IS NULL到外部表中会使其失败。

于 2016-08-10T01:05:43.003 回答