MySQL声称我可以使用SELECT中不在GROUPBY中的列,但我不能使用同等性能的列
MySQL文档指出,不管SQL标准怎么说,在SELECT子句中使用不在GROUPBY子句中的列是可以的,只要它们在功能上依赖于分组键 MySQL通过so扩展了GROUP的使用 您可以使用非聚集列 或选择列表中的计算 不显示在组中的 条款您可以使用此功能来 通过避免 不必要的列排序和 分组。例如,您不需要 组中的customer.name 以下查询:MySQL声称我可以使用SELECT中不在GROUPBY中的列,但我不能使用同等性能的列,mysql,optimization,indexing,group-by,Mysql,Optimization,Indexing,Group By,MySQL文档指出,不管SQL标准怎么说,在SELECT子句中使用不在GROUPBY子句中的列是可以的,只要它们在功能上依赖于分组键 MySQL通过so扩展了GROUP的使用 您可以使用非聚集列 或选择列表中的计算 不显示在组中的 条款您可以使用此功能来 通过避免 不必要的列排序和 分组。例如,您不需要 组中的customer.name 以下查询: SELECT order.custid, customer.name, MAX(payments) FROM order,customer
SELECT order.custid, customer.name,
MAX(payments) FROM order,customer
WHERE order.custid = customer.custid
GROUP BY order.custid;
标准
SQL,则必须添加
customer.name添加到GROUP BY子句。
在MySQL中,名称是多余的
听起来很合理。然而,尽管我可以选择这些列,但它似乎对性能有不利影响
EXPLAIN SELECT o.id FROM objects o GROUP BY o.id;
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
| 1 | SIMPLE | o | range | NULL | PRIMARY | 3 | NULL | 5262 | Using index for group-by |
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
我意识到这个问题相当愚蠢;它只是具有相同问题的更复杂查询的最简单版本。当只选择I group by的主键ID时,MySQL使用主键索引。但是,当我包含其他列时,MySQL没有
EXPLAIN SELECT o.id, o.name FROM objects o GROUP BY o.id;
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| 1 | SIMPLE | o | ALL | NULL | NULL | NULL | NULL | 5261 | Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
使用filesort而不是索引真的让我很沮丧。我目前希望从此表中选择*,因此希望避免重复组中的所有列并为它们编制索引。有没有办法让MySQL像我所期望的那样使用主键索引?为group by使用一个派生表,然后重新连接到您想要从中选择的任何表上,因为看起来没有一个简单的答案,所以我现在选择一个便宜的解决方案 我要做的事情如下:
SELECT o1.* FROM objects o1 WHERE o1.id IN (SELECT o2.id FROM objects o2 WHERE mycondition GROUP BY o2.id)
然而,根据解释,MySQL优化器认为子查询是依赖的,这总是一个非常非常糟糕的性能杀手。我认为这是查询优化器中的一个缺陷,因为它是同一个表,尽管它有别名。因此,我将使用一个查询来获取ID,并将它们放入第二个获取o.*的查询中。它具有合理的性能,并且不会太痛苦
这个问题仍然可以用更干净的解决方案来回答,这些解决方案即使没有更好的效果,也可以表现得更好:在第一个查询中,您访问的唯一字段是索引,因此mysql只需查看索引文件。但是在第二个查询中,您现在从表本身提取一列,这也需要读取表数据。第一个查询并没有像使用WHERE子句那样使用主键索引。它只对groupby使用它,但它仍然在查看索引中的每个条目 第一个查询和第二个查询之间的区别在于,第二个查询必须查看完整表中的每一行,即表扫描,而不仅仅是索引中的每一个主键值 就优化而言,如果您的实际查询没有示例中的累积函数SUM、COUNT等,那么只需执行以下操作,您就会看到一个重大改进:
SELECT DISTINCT o.id, o.name FROM objects o
但是,如果您的简单示例中只有这样的情况,并且您的查询确实需要一个组,那么您的下一个最佳选择是增加变量,以允许同时在内存中容纳更多的行。我可以在技术上使用子查询和派生表,但MySQL优化器至少以其当前形式存在,在Debian repositories的最新版本中,将它们视为依赖子查询,而不是提前运行然后运行的查询。我打赌这是因为它是同一张表,有不同的别名。