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

时间:2014-12-19 15:48:48

标签: mysql group-by left-join isnull

我使用了' LEFT JOIN IS NULL'为了进行分组,我认为这是将记录分组到一个字段并通过每个组中的另一个字段找到最大值的记录的最佳方法。

对于isntance,

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毫秒。

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

第一次查询的EXPLAIN

"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"

EXPLAIN for second query

"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"

1 个答案:

答案 0 :(得分:0)

将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执行这两个语句...我敢打赌它会像拇指一样痛苦。