【问题标题】:Why this mysql query (with is null check) is so slower than this other one?为什么这个 mysql 查询(带有空检查)比另一个慢?
【发布时间】:2016-12-16 04:53:50
【问题描述】:

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

【问题讨论】:

  • 这真是奇怪的结果,你确定不是页面缓存的原因吗?

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


【解决方案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 添加到外部表中会使其失效。

【讨论】:

  • 奇怪的事情(至少对我来说)是“快速”查询(带有“is null”)不使用第二个表的任何索引,但检查相同数量的行并且工作速度快 300 倍.
  • 为什么不使用左连接?现有的查询通常表现很差。
  • @TaylorN 。 . .为什么要使用LEFT JOIN?首先,这会将所有内容都保留在第一个表中。其次,它可能会产生重复,从而需要删除重复。
  • 我稍微误读了查询。但是,无论如何,根据我的经验,我仍然认为 LEFT JOIN 与 DISTINCT 结合会表现更好。
猜你喜欢
  • 2015-11-16
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
  • 2013-07-09
  • 1970-01-01
  • 2017-10-26
  • 2011-03-11
  • 2012-06-13
相关资源
最近更新 更多