MySQL 比较 'LEFT JOIN IS NULL' 与 'GROUP BY'

标签 mysql group-by left-join isnull

我经常使用“LEFT JOIN IS NULL”进行分组,我认为这是按一个字段对记录进行分组并通过每组中的另一个字段查找具有最大值的记录的最佳方式。

例如,

SELECT i.* FROM instance i  
LEFT JOIN instance itemp on itemp.client = i.client AND itemp.updated_at > i.updated_at 
WHERE itemp.id IS NULL 

为每个客户提供最新的记录。

但是对于小型数据库来说,这个查询速度非常慢(约 200 秒)

  • “实例”记录总数:27000
  • 其中 90% (24000) 属于一个客户
  • 其中 10% 通过其他 5 个客户均匀分配
  • “updated_at”字段的值分布非常均匀
  • 有索引 (client、updated_at) 和 (client)

同时进行分组查询

SELECT inst.* FROM instance inst,
(
    SELECT i.client AS cl, MAX(i.updated_at) AS up 
    FROM instance i     
    GROUP BY i.client
) AS max_values
WHERE 
inst.client = max_values.cl AND inst.updated_at = max_values.up

只需 63 毫秒。

为什么第一个查询与第二个查询相比如此慢?

第一个查询的解释

"id"    "select_type"   "table" "type"  "possible_keys" "key"   "key_len"   "ref"   "rows"  "filtered"  "Extra"
"1" "SIMPLE"    "i" "ALL"   \N  \N  \N  \N  "27247" "100.00"    ""
"1" "SIMPLE"    "itemp" "ref"   "updated_at,client,client_updated_at"   "client_updated_at" "183"   "schibsted_auth.i.client"   "908"   "100.00"    "Using where; Using index; Not exists"

第二个查询的解释

"id"    "select_type"   "table" "type"  "possible_keys" "key"   "key_len"   "ref"   "rows"  "filtered"  "Extra"
"1" "PRIMARY"   "<derived2>"    "ALL"   \N  \N  \N  \N  "8" "100.00"    ""
"1" "PRIMARY"   "inst"  "ref"   "updated_at,client,client_updated_at"   "updated_at"    "8" "max_values.up" "1" "100.00"    "Using where"
"2" "DERIVED"   "i" "range" \N  "client_updated_at" "183"   \N  "31"    "100.00"    "Using index for group-by"

最佳答案

将 EXPLAIN EXTENDED 放在两个查询前面并查看输入(这可能会派上用场: http://www.sitepoint.com/using-explain-to-write-better-mysql-queries/ )。最有可能的是,缓慢与 Updated_at 连接条件有关。

您的第一个表正在使用 itemp.client = i.client AND itemp.updated_at > i.updated_at 进行自联接。

后者实际上是与 inst.client = max_values.cl AND inst.updated_at = max_values.up 的内部联接,由于 Updated_at 上的相等引用,这反过来会更快。这尤其重要,因为您的数据存在偏差,并且您的客户之一拥有 24000 条与之关联的记录。应用程序很可能正在比较 24000 个 itemp.updated_at 值中的哪一个大于 24000 个 i.updated_at 值中的哪一个。在第二个查询中,它不必执行昂贵的组合连接。它只是匹配平等并继续前进。

再说一遍,我并不是 100% 清楚这就是正在发生的事情。但我敢打赌,如果您将 EXPLAIN EXTENDED 放在两个查询前面,这就是您将看到的内容。对于具有 24000 个观察值的一位客户,查看 EXPLAIN EXTENDED 会特别有用。为该客户端添加一个 where 子句,并使用 EXPLAIN... 执行这两个语句...我打赌它会像一个酸痛的拇指一样突出。

关于MySQL 比较 'LEFT JOIN IS NULL' 与 'GROUP BY',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27569389/

相关文章:

php - 无法将大量数据导入数据库phpmyadmin

mysql - mysql中如何限制变量的增量

c# - 数据表分组,用逗号分隔

mysql - Left Join 基于字段值

MySQL 排除和要求

mysql - 连接多个表并返回零(如果不是排在一个表中)

mysql - JSF2.0 : Mojibake for primefaces4. 0

MySQL 对每组的最后 X 行求和

MySQL 嵌套 SELECT 太慢

php - Laravel 5.1 Mysql NULL