这是我一直面临的问题。幸运的是,有一个很好的小技巧可以做到这一点:
SELECT
client_id,
SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY created DESC),",",1) AS `id`
FROM client_directory_data
WHERE verified = 1
GROUP BY client_id
如果你想要整行,你可以像这样加入它:
SELECT
*
FROM (
SELECT
client_id,
SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY created DESC),",",1) AS `id`
FROM client_directory_data
WHERE verified = 1
GROUP BY client_id
) ids
JOIN client_directory_data USING (id);
当然,如果您无论如何都按索引字段排序(因此无论如何您都可以有效地加入),最好使用MAX(id) AS id
,尽管它实际上对性能影响很小。使用 MAX() 的主要原因实际上是为了让代码更简单一些。它还避免了如果字段包含逗号(您可以使用组 concat 的不同分隔符来解决)或达到最大 GROUP_CONCAT 长度(可以扩展SET group_concat_max_len = xxx;
并且无论如何只会导致警告)时可能遇到的陷阱。
我可以理解为什么这在直觉上看起来会出现性能问题,但它实际上是我为这些查询找到的最佳性能方法——尤其是在大型表上。
以下是我从当前可用的一些较大的表中获取的一些基准,比较了这个线程中的三种方法。
查询 A:(约 5,000 条记录,约 900 条结果,非索引字段)
- GROUP_CONCAT 方法:0.0100 秒
- MAX方法:0.102秒
- LEFT JOIN 方法:0.0082 秒
查询 B:(~300,000 条记录,~95,000 个结果)
- GROUP_CONCAT 方法:1.8618 秒
- MAX方法:1.7904秒
- LEFT JOIN 方法:6.4649 秒
查询 C:(~300,000 条记录,~7 个结果)
- GROUP_CONCAT 方法:0.103 秒
- MAX方法:0.0102秒
- LEFT JOIN 方法:(4小时后我感到无聊)
查询 D:(约 500,000 条记录,约 5,000 个被分组的字段的不同值)
- GROUP 方法:0.1355 秒
- MAX 方法:0.0429 秒
- LEFT JOIN 方法:(10分钟后我觉得无聊)