【问题标题】:Huge performance difference when using GROUP BY vs DISTINCT使用 GROUP BY 与 DISTINCT 时的巨大性能差异
【发布时间】:2011-12-18 03:23:09
【问题描述】:

我正在使用包含 500 000 个条目的表在 HSQLDB 服务器上执行一些测试。该表没有索引。有 5000 个不同的业务密钥。我需要一份他们的清单。

我自然是从DISTINCT 查询开始的:

SELECT DISTINCT business_key
FROM memory
WHERE concept <> 'case'   OR 
      attrib  <> 'status' OR 
      value   <> 'closed';

大约需要 90 秒!!!

然后我尝试使用GROUP BY

SELECT business_key
FROM memory
WHERE concept <> 'case'   OR 
      attrib  <> 'status' OR
      value   <> 'closed';
GROUP BY business_key

而且需要 1 秒!!!

试图找出我运行 EXLAIN PLAN FOR 的区别,但它似乎为两个查询提供了相同的信息。

EXLAIN PLAN FOR DISTINCT ...

isAggregated=[false]
columns=[
  COLUMN: PUBLIC.MEMORY.BUSINESS_KEY
]
[range variable 1
  join type=INNER
  table=MEMORY
  alias=M
  access=FULL SCAN
  condition = [    index=SYS_IDX_SYS_PK_10057_10058
    other condition=[
    OR arg_left=[
     OR arg_left=[
      NOT_EQUAL arg_left=[
       COLUMN: PUBLIC.MEMORY.CONCEPT] arg_right=[
       VALUE = case, TYPE = CHARACTER]] arg_right=[
      NOT_EQUAL arg_left=[
       COLUMN: PUBLIC.MEMORY.ATTRIB] arg_right=[
       VALUE = status, TYPE = CHARACTER]]] arg_right=[
     NOT_EQUAL arg_left=[
      COLUMN: PUBLIC.MEMORY.VALUE] arg_right=[
      VALUE = closed, TYPE = CHARACTER]]]
  ]
]]
PARAMETERS=[]
SUBQUERIES[]
Object References
PUBLIC.MEMORY
PUBLIC.MEMORY.CONCEPT
PUBLIC.MEMORY.ATTRIB
PUBLIC.MEMORY.VALUE
PUBLIC.MEMORY.BUSINESS_KEY
Read Locks
PUBLIC.MEMORY
WriteLocks

EXLAIN PLAN FOR SELECT ... GROUP BY ...

isDistinctSelect=[false]
isGrouped=[true]
isAggregated=[false]
columns=[
  COLUMN: PUBLIC.MEMORY.BUSINESS_KEY
]
[range variable 1
  join type=INNER
  table=MEMORY
  alias=M
  access=FULL SCAN
  condition = [    index=SYS_IDX_SYS_PK_10057_10058
    other condition=[
    OR arg_left=[
     OR arg_left=[
      NOT_EQUAL arg_left=[
       COLUMN: PUBLIC.MEMORY.CONCEPT] arg_right=[
       VALUE = case, TYPE = CHARACTER]] arg_right=[
      NOT_EQUAL arg_left=[
       COLUMN: PUBLIC.MEMORY.ATTRIB] arg_right=[
       VALUE = status, TYPE = CHARACTER]]] arg_right=[
     NOT_EQUAL arg_left=[
      COLUMN: PUBLIC.MEMORY.VALUE] arg_right=[
      VALUE = closed, TYPE = CHARACTER]]]
  ]
]]
groupColumns=[
COLUMN: PUBLIC.MEMORY.BUSINESS_KEY]
PARAMETERS=[]
SUBQUERIES[]
Object References
PUBLIC.MEMORY
PUBLIC.MEMORY.CONCEPT
PUBLIC.MEMORY.ATTRIB
PUBLIC.MEMORY.VALUE
PUBLIC.MEMORY.BUSINESS_KEY
Read Locks
PUBLIC.MEMORY
WriteLocks

编辑

我做了额外的测试。 HSQLDB 中有 500 000 条记录以及所有不同的业务密钥,DISTINCT 的性能现在更好 - 3 秒,而 GROUP BY 大约需要 9 秒。

MySQL 中,两个查询都执行相同的操作:

MySQL:500 000 行 - 5 000 个不同的业务键: 两个查询:0.5 秒 MySQL:500 000 行 - 所有不同的业务键: SELECT DISTINCT ... - 11 秒 SELECT ... GROUP BY business_key - 13 秒

所以问题只与HSQLDB有关。

如果有人能解释为什么会有如此巨大的差异,我将不胜感激。

【问题讨论】:

  • 请显示EXPLAIN PLAN 的结果,并在运行GROUP BY 后尝试运行DISTINCT查询,看看是否某些缓存会影响时间...
  • 假设您为每个查询获得相同的计划,听起来好像表数据或结果已被缓存。
  • 我运行了很多次,相信缓存不是问题。我正在发布EXLAIN PLAN FOR 输出。
  • 我有一个想法,但我真的不确定 - 请尝试 SELECT DISTINCT business_key FROM (SELECT business_key FROM memory WHERE concept &lt;&gt; 'case' or attrib &lt;&gt; 'status' or value &lt;&gt; 'closed') - 如果我的想法是正确的,这应该会显示与 GROUP BY 相同的性能。
  • @Yahia:仍然很慢 - 94 秒。我将在 MySQL 中运行相同的查询,看看会显示什么

标签: sql performance group-by distinct hsqldb


【解决方案1】:

这两个查询表达了同一个问题。显然查询优化器选择了两种不同的执行计划。我的猜测是distinct 方法的执行方式如下:

  • 将所有business_key 值复制到临时表中
  • 对临时表进行排序
  • 扫描临时表,返回与之前不同的每一项

group by 可以这样执行:

  • 扫描整个表,将business key 的每个值存储在哈希表中
  • 返回哈希表的键

第一种方法优化了内存使用:当临时表的一部分必须被换出时,它仍然可以很好地执行。第二种方法优化了速度,但如果有很多不同的键,则可能需要大量内存。

由于您要么有足够的内存或很少有不同的键,因此第二种方法优于第一种。两个执行计划之间出现 10 倍甚至 100 倍的性能差异并不罕见。

【讨论】:

  • 感谢您的回复。从EXPLAIN 输出中您的猜测是否显而易见?在我看来两者都一样。
  • 据我所知,该计划并未指定如何执行连接。我什至不确定它为什么会执行连接。可能需要 HSQLDB 专家才能阅读解释输出。
  • 如答案所示,第二种方法使用更多内存,并且可能过于频繁地命中垃圾回收 (GC)。如果增加 JVM 内存分配,两次查询时间应该不会有太大差异。
  • 我通过在表中输入所有不同的键进行了额外的测试(见上文)。你觉得结果能证明你的观点吗?非常感谢。
  • 能否请一位 SME 专家通过示例更详细地解释这一点...我已经多次遇到此问题,但似乎无法解决...我知道解决方法,但我想知道如何以及为什么
猜你喜欢
  • 2023-03-10
  • 2019-03-09
  • 2014-06-21
  • 2010-09-30
  • 2019-04-21
  • 2010-10-15
  • 2011-02-02
  • 1970-01-01
  • 2013-02-18
相关资源
最近更新 更多