Distinct和Group By在SQL查询中是两个常用的关键字。它们的作用是用于去除重复值和进行分组操作。 Distinct用于从查询结果中去除重复行,只返回唯一的结果。它可以应用于一个或多个列。例如,SELECT DISTINCT column1, column2 FROM table; 将返回唯一的column1和column2的组合。 Group By用于将查询结果按照一个或多个列进行分组。它将相同值的行放在一起,并对每组应用聚合函数(如SUM、COUNT、AVG等)。例如,SELECT c

20 浏览
0 Comments

Distinct和Group By在SQL查询中是两个常用的关键字。它们的作用是用于去除重复值和进行分组操作。 Distinct用于从查询结果中去除重复行,只返回唯一的结果。它可以应用于一个或多个列。例如,SELECT DISTINCT column1, column2 FROM table; 将返回唯一的column1和column2的组合。 Group By用于将查询结果按照一个或多个列进行分组。它将相同值的行放在一起,并对每组应用聚合函数(如SUM、COUNT、AVG等)。例如,SELECT c

我有两个表格如下。\n\'订单\'表格有21886行。\n

CREATE TABLE `order` (
  `id` bigint(20) unsigned NOT NULL,
  `reg_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_reg_date` (`reg_date`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
CREATE TABLE `order_detail_products` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `order_id` bigint(20) unsigned NOT NULL,
  `order_detail_id` int(11) NOT NULL,
  `prod_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_order_detail_id` (`order_detail_id`,`prod_id`),
  KEY `idx_order_id` (`order_id`,`order_detail_id`,`prod_id`)
) ENGINE=InnoDB AUTO_INCREMENT=572375 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

\n我的问题如下。\nMariaDB [test]> explain\n -> SELECT DISTINCT A.id\n -> FROM order A\n -> JOIN order_detail_products B ON A.id = B.order_id\n -> ORDER BY A.reg_date DESC LIMIT 100, 30;\n+------+-------------+-------+-------+---------------+--------------+---------+-------------------+-------+----------------------------------------------+\n| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |\n+------+-------------+-------+-------+---------------+--------------+---------+-------------------+-------+----------------------------------------------+\n| 1 | SIMPLE | A | index | PRIMARY | idx_reg_date | 8 | NULL | 22151 | Using index; Using temporary; Using filesort |\n| 1 | SIMPLE | B | ref | idx_order_id | idx_order_id | 8 | bom_20140804.A.id | 2 | Using index; Distinct |\n+------+-------------+-------+-------+---------------+--------------+---------+-------------------+-------+----------------------------------------------+\n2 rows in set (0.00 sec)\nMariaDB [test]> explain\n -> SELECT A.id\n -> FROM order A\n -> JOIN order_detail_products B ON A.id = B.order_id\n -> GROUP BY A.id\n -> ORDER BY A.reg_date DESC LIMIT 100, 30;\n+------+-------------+-------+-------+---------------+--------------+---------+-------------------+------+------------------------------+\n| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |\n+------+-------------+-------+-------+---------------+--------------+---------+-------------------+------+------------------------------+\n| 1 | SIMPLE | A | index | PRIMARY | idx_reg_date | 8 | NULL | 65 | Using index; Using temporary |\n| 1 | SIMPLE | B | ref | idx_order_id | idx_order_id | 8 | bom_20140804.A.id | 2 | Using index |\n+------+-------------+-------+-------+---------------+--------------+---------+-------------------+------+------------------------------+\n\n如上所述,两个查询返回相同结果,但使用DISTINCT太慢(解释中显示了太多行)。\n有什么区别?

0
0 Comments

Distinct vs Group By是一个常见的问题,出现的原因是在使用select distinct时,通过匹配另一个表的参数,破坏了索引,导致查询变得较慢。这种情况下,通常使用Group By会更快。

解决这个问题的方法是使用Group By来替代select distinct。通过使用Group By,可以在查询中保持索引的有效性,提高查询性能。

以下是一个示例代码,演示了如何使用Group By来替代select distinct的情况:

SELECT column1, column2
FROM table
GROUP BY column1, column2

通过将需要去重的列作为Group By的参数,可以达到与select distinct相同的效果。

需要注意的是,使用Group By时需要确保所有的列都包含在Group By中,以避免出现错误的结果。

总结起来,当需要对查询结果进行去重时,通常情况下使用select distinct是更快的方法。但是,如果在查询中涉及到匹配另一个表的参数,破坏了索引,导致查询变慢,则可以考虑使用Group By来替代select distinct,以提高查询性能。

0
0 Comments

在这篇文章中,我们将讨论使用DISTINCT和GROUP BY的区别,以及出现这个问题的原因和解决方法。

通常建议使用DISTINCT而不是GROUP BY,因为这是你真正想要的,让优化器选择“最佳”的执行计划。然而,没有一个优化器是完美的。使用DISTINCT查询时,优化器可以有更多的执行计划选项。但这也意味着它有更多的选择来选择一个糟糕的计划。

你提到DISTINCT查询很慢,但没有提供具体的数字。在我的测试中(在MariaDB 10.0.19和10.3.13上进行,行数是原来的10倍),DISTINCT查询只比GROUP BY查询慢25%(562ms/453ms)。EXPLAIN结果毫无帮助。它甚至“撒谎”。使用LIMIT 100, 30,它至少需要读取130行(这是我的EXPLAIN实际上对GROUP BY显示的内容),但它显示了65行。

我无法解释执行时间上的25%差异,但似乎引擎在任何情况下都在进行全表/索引扫描,并在跳过100行并选择30行之前对结果进行排序。

最好的计划可能是:

从idx_reg_date索引(表A)中按降序逐个读取行

在idx_order_id索引(表B)中查找是否有匹配项

跳过100个匹配的行

发送30个匹配的行

退出

如果A表中有10%的行与B表中的行不匹配,那么这个计划可能会读取大约143行。

我尽力通过以下方法来强制执行此计划:

SELECT A.id

FROM `order` A

WHERE EXISTS (SELECT * FROM order_detail_products B WHERE A.id = B.order_id)

ORDER BY A.reg_date DESC

LIMIT 30

OFFSET 100

这个查询在156毫秒内返回相同的结果(比GROUP BY快3倍)。但这仍然太慢了。而且它可能仍在读取表A中的所有行。

我们可以通过一个“小”子查询技巧来证明更好的计划可能存在:

SELECT A.id

FROM (

SELECT id, reg_date

FROM `order`

ORDER BY reg_date DESC

LIMIT 1000

) A

WHERE EXISTS (SELECT * FROM order_detail_products B WHERE A.id = B.order_id)

ORDER BY A.reg_date DESC

LIMIT 30

OFFSET 100

这个查询在“零时间”(约0毫秒)内执行,并在我的测试数据上返回相同的结果。虽然它不是100%可靠,但它表明优化器的工作并不好。

所以我的结论是:

优化器并不总是做得最好,有时需要帮助

即使我们知道“最佳计划”,我们也不能总是强制执行它

DISTINCT并不总是比GROUP BY更快

当所有子句都无法使用索引时,情况会变得相当棘手

0