【问题标题】:UNION vs GROUP BY or better solutionUNION vs GROUP BY 或更好的解决方案
【发布时间】:2018-05-08 08:46:05
【问题描述】:

我有一种情况,我在数据库表中有几十万行,比如说 8 列,其中前两列被索引(每列两个索引,两列一个复合索引),我有两个带有 group by 和 union 的 SQL 查询:

SELECT MIN(columnOne), columnTwo FROM MyTable
WHERE columnTwo IN (1,2,3)
GROUP BY columnTwo

SELECT MIN(columnOne), columnTwo FROM MyTable WHERE columnTwo = 1
UNION
SELECT MIN(columnOne), columnTwo FROM MyTable WHERE columnTwo = 2
UNION
SELECT MIN(columnOne), columnTwo FROM MyTable WHERE columnTwo = 3

而且,使用 unions 的第二种方法的效果似乎比第一种方法快 两倍(有时更多)

我在 Python 中执行这个查询,所以第一个是一个衬垫,第二个是我需要生成的。

我想知道第二种方法是否正常,可能还有第三种我不知道的方法?

更新:

所有查询中的

columnTwocolumnOne 字段不是唯一的

例子

# columnOne columnTwo
1 a         a        
2 b         b        
3 c         b        
4 d         a        
...

用 group by 解释查询:

id  select_type    table        type    possible_keys               key       key_len           ref     rows    Extra
1   SIMPLE         MyTable      index   secondColIndex,bothColIndex bothColIndex    12                 1623713   Using where

Explain for query with unions 显示如下:

id  select_type    table        type    possible_keys               key       key_len   ref     rows    Extra
1   PRIMARY        MyTable      ref     secondColIndex,bothColIndex bothColIndex    4   const   217472  Using where
2   UNION          MyTable      ref     secondColIndex,bothColIndex bothColIndex    4   const   185832  Using where
3   UNION          MyTable      ref     secondColIndex,bothColIndex bothColIndex    4   const   175572  Using where
    UNION RESULT   <union1,2,3> ALL                                     Using temporary

MyTable 中的索引:

Table, Non_unique, Key_name, Seq_in_index, Column_name, Collation, Cardinality, Sub_part, Packed, Null, Index_type, Comment, Index_comment
MyTable, 0, PRIMARY, 1, Id, A, 1623713, , , , BTREE, , 
MyTable, 1, columnOneIndex, 1, columnOne, A, 1623713, , , , BTREE, , 
MyTable, 1, columnTwoIndex, 1, columnTwo, A, 5737, , , , BTREE, , 
MyTable, 1, bothColumnsIndex, 1, columnTwo, A, 5171, , , , BTREE, , 
MyTable, 1, bothColumnsIndex, 2, columnOne, A, 1623713, , , , BTREE, , 

【问题讨论】:

  • 好问题。冷/热数据差异?
  • 但是您的查询不一样 - 带有“union”的查询选择了 3 条记录(并且在那里使用 min 没有意义,因为我们通过 id 选择了一条记录,我是假设 id 是唯一的),而第一个选择 1 条宽度最小的记录。
  • 我认为即使 id 不是唯一的,由于“联合”查询,您仍然会得到 3 行,因此您实际上并没有得到一个 min 值,但是每组 3 个最小值。
  • 是的,我需要为每个组获取 3 行最小值
  • 我看起来像“group by”查询扫描了 160 万条记录,而联合查询中的“rows”总和大约为 500K(少三倍)。两列的索引如何?根据this,您可能需要它是(columnTwo, columnOne) - 顺序很重要,columnTwo 应该排在第一位。

标签: mysql sql select group-by union


【解决方案1】:

您所看到的是由于 MySQL 优化器的限制(在最新版本中可能会有很大改进)。 GROUP BY 几乎总是会导致文件排序,从而限制索引的使用。

一种替代方法本质上只是UNION 版本的简化,但使用相关子查询:

SELECT x.columnTwo,
       (SELECT MIN(columnOne)
        FROM myTable t
        WHERE t.columnTwo = x.columnTwo
       ) as min_columnOne
FROM (SELECT 1 as columnTwo UNION ALL
      SELECT 2 as columnTwo UNION ALL
      SELECT 3 as columnTwo
     ) x;

这应该与您使用UNION 的版本具有基本相同的性能。相关子查询应使用索引进行计算。

【讨论】:

  • 哇,实际上这比联合更快,它给了我 0.3 秒,而对于联合来说,它接近 1.5 秒
猜你喜欢
  • 2011-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多