2

嗨,我对 mysql select 语句有疑问,我无法理解,

表client_directory_data

id int,已验证 int,client_id int,创建时间戳,描述 longtext

select * from client_directory_data where verify = 1 order by created desc

但这会为每个 client_id 选择多行

我需要做的是选择每个经过验证的client_id = 1,但只获取每个client_id 的最新行,我希望这是有道理的。

4

3 回答 3

4

这是我一直面临的问题。幸运的是,有一个很好的小技巧可以做到这一点:

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分钟后我觉得无聊)
于 2012-07-05T11:11:22.020 回答
3

这是有道理的,是一个经典的问题。

假设the most recent row is the one with highest id,您可以使用:

SELECT *
FROM client_directory_data c
LEFT JOIN client_directory_data d ON c.client_id = d.client_id AND d.verified = 1 AND d.id > c.id
WHERE d.id IS NULL
    AND c.verified = 1;

您可以在此处了解此查询模式。

于 2012-07-05T10:53:42.290 回答
0

将 id 作为表 client_directory_data 的主键

于 2012-07-05T10:55:27.810 回答