使用分组依据与不同时的巨大性能差异


80

我正在HSQLDB包含500 000项的表的服务器上执行一些测试。该表没有索引。有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

编辑:我做了其他测试。拥有500 000条HSQLDB具有不同业务键的记录,DISTINCT现在的性能更好-3秒,GROUP BY而花费了大约9秒。

MySQL两个查询中,预执行都相同:

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

因此,问题仅与HSQLDB

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


2
请显示EXPLAIN PLANAND的结果,并在运行DISTINCT后尝试运行查询,GROUP BY以查看是否某些缓存使时间错了……
Yahia

如果您为每个查询获得相同的计划,这听起来像是表数据或结果已被缓存。
2011年

我跑了很多遍,以至于认为缓存不是问题。我正在发布EXLAIN PLAN FOR输出。
马丁·迪米特洛夫

我有一个主意,但我真的不确定-请尝试SELECT DISTINCT business_key FROM (SELECT business_key FROM memory WHERE concept <> 'case' or attrib <> 'status' or value <> 'closed')-GROUP BY如果我的主意正确,应该可以显示出与您看到的相同的性能。
Yahia

@Yahia:仍然很慢-94秒。我将在MySQL中运行相同的查询以查看显示的内容
Martin Dimitrov

Answers:


75

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

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

group by会等执行:

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

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

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


谢谢回复。从EXPLAIN输出中可以明显看出您的猜测吗?两者在我看来都一样。
马丁·迪米特洛夫

据我所知,该计划未指定如何执行联接。我什至不知道为什么要执行联接。HSQLDB专家可能需要阅读说明输出。
2011年

如答案所示,第二种方法使用更多的内存,并且可能会频繁出现垃圾回收(GC)。如果增加JVM内存分配,则两个查询时间之间应该不会有太大差异。
2011年

我通过在表中输入所有不同的键进行了其他测试(请参见上文)。您认为结果证明您的观点吗?非常感谢。
马丁·迪米特洛夫

2
中小企业专家能否通过示例更详细地说明这一点……我已经多次遇到这个问题,但是似乎并没有解决……我知道解决方法,但是我想知道为什么以及为什么
singhswat 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.