Подтвердить что ты не робот

Огромная разница в производительности при использовании группы по vs

Я выполняю несколько тестов на сервере 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 секунды, vs GROUP BY, которая заняла около 9 секунд.

В MySQL оба запроса заготовят одно и то же:

MySQL: 500 000 строк - 5 000 различных бизнес-ключей: Оба запроса: 0,5 секунды MySQL: 500 000 строк - все отдельные бизнес-ключи: SELECT DISTINCT ... - 11 секунд SELECT ... GROUP BY business_key - 13 секунд

Таким образом, проблема связана только с HSQLDB.

Буду очень признателен, если кто-нибудь сможет объяснить, почему существует такая радикальная разница.

4b9b3361

Ответ 1

Два запроса выражают один и тот же вопрос. По-видимому, оптимизатор запросов выбирает два разных плана выполнения. Я предполагаю, что подход distinct выполняется так:

  • Скопировать все значения business_key во временную таблицу
  • Сортировка временной таблицы
  • Сканировать временную таблицу, возвращая каждый элемент, отличный от того, который был перед ним

group by может выполняться как:

  • Сканировать полную таблицу, сохраняя каждое значение business key в хеш-таблице
  • Возвращает ключи хэш-таблицы

Первый метод оптимизирует использование памяти: он все равно будет достаточно хорошо работать, когда часть временной таблицы должна быть заменена. Второй метод оптимизируется для скорости, но потенциально требует большого объема памяти, если имеется много разных ключей.

Поскольку у вас либо достаточно памяти, либо несколько разных ключей, второй метод превосходит первый. Не удивительно видеть разницу в производительности 10x или даже 100x между двумя планами выполнения.