mysql - 为什么这个 mysql 查询(带有 is null 检查)比另一个查询慢那么多?

标签 mysql sql database relational-database database-tuning

我对“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));

enter image description here

快速查询:

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 条记录。

最佳答案

令我惊讶的是两者都很快。我建议用 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),目标都是进行“半连接”。也就是说,只对第一行进行匹配而不是所有匹配。这是一个重要的效率,因为它允许查询避免重复删除。

我推测问题出在 的优化上——通常这会导致 JOIN 算法效率低下。但是,在您的第一种情况下,MySQL 可能很聪明。但是将 IS NULL 添加到外表会将它抛出。

关于mysql - 为什么这个 mysql 查询(带有 is null 检查)比另一个查询慢那么多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38862671/

相关文章:

sql - 在 Hive 中将单行列拆分为多列

java - java中通过JDBC实现数据库独立性

database - 按降序索引日期列是个好主意吗?

mysql - 列可以为 Nullable、Unsigned 和外键吗?

mysql - 数组数据类型插入MySQL

mysql - 将 mysql 数据分布到多个磁盘

java - hibernate HqlL : Count and Group By including zero?

如果记录的 id 和用户名没有出现在第二个表中,MySQL 会从一个表中选择记录

php - fatal error : Call to a member function bind_param() on boolean in php while inputing String from Android app

php - 维护数据库连接或在需要时连接?