为什么这个mysql查询(使用null检查)比其他查询慢?

时间:2016-08-10 01:01:10

标签: mysql sql database relational-database database-tuning

我怀疑“IS NULL”MySQL检查。我有这2个查询。第一个在大约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));

whole

快速查询:

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

enter image description here

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

1 个答案:

答案 0 :(得分:0)

我很惊讶两者都很快。我建议用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添加到外部表会将其抛弃。