2017-02-10 91 views
0

У меня есть очень простой запрос на столе с 60 миллионами строк:Оптимизация очень медленно выберите максимальную группу по запросу на Sybase ASE 15,5

select id, max(version) from mytable group by id

возвращает 6 миллионов записей и занимает больше, чем за один час бежать. Мне просто нужно запустить его один раз, потому что я переношу записи в другую новую таблицу, которую я постоянно обновляю.

Я попробовал несколько вещей, которые не работали для меня, но которые часто предлагаются здесь на StackOverflow:

  1. внутренний запрос с select top 1/order by desc: она не поддерживается в Sybase ASE
  2. left outer join where a.version < b.version and b.version is null: Я прервала запрос после более чем одного часа и всего лишь сто тысяч записей был найден

Я понимаю, что Sybase должен выполнить полное сканирование.

Почему сканирование должно быть настолько медленным?

Является ли медлительность из-за экземпляра Sybase ASE сама по себе или специфична для запроса?

Каковы мои возможности для сокращения времени выполнения запроса?

ответ

0

Так, наконец, некластеризованным индекс (идентификатор, версия убыв) сделал трюк без необходимости менять что-либо в запросе. Создание индекса также занимает один час, и запрос отвечает за несколько секунд. Но я думаю, что это все же лучше, чем наличие другой таблицы, которая может вызвать проблемы с целостностью данных.

1

Я не знаком с оптимизацией Sybase. Однако ваш запрос выполняется очень медленно. Вот две идеи.

Сначала добавьте индекс на mytable(id, version desc). Как минимум, это , охватывающий индекс для запроса, что означает, что все используемые столбцы указаны в индексе. Sybase, вероятно, достаточно умна, чтобы устранить group by.

Другой вариант использует тот же индекс, но с корреляцией подзапроса:

select t.id 
from mytable t 
where t.version = (select max(t2.version) 
        from mytable t2 
        where t2.id = t.id 
       ); 

Это будет полное сканирование таблицы (немного дорогой, но не стоит в часе) и поиск индекса по каждой строке (довольно дешево). Преимущество этого подхода состоит в том, что вы можете выбрать все нужные столбцы. Недостатком является то, что если две строки имеют одну и ту же максимальную версию для id, вы получите оба в наборе результатов.

+0

Спасибо за ваш ответ. Я забыл упомянуть, что в этой таблице уже есть кластеризованный индекс, и его сброс не является вариантом. Кроме того, создание индекса и статистика обновления не занимают меньше часа. –

+0

@Nicolas. , , Я ничего не упоминал о кластеризованном индексе или опускании любого существующего индекса. –

+0

"добавить индекс на mytable (id, version desc)" вы говорите о некластеризованном индексе? –

0

Редактировать: Здесь Николас более точный ответ. У меня нет особого опыта работы с Sybase, но я заработал опыт работы с тонами данных с довольно маленьким сервером на Sql Server. Из этого опыта я узнаю, что, когда вы работаете с большим количеством данных, и на вашем сервере не хватает памяти для работы с этим объемом данных, вы столкнетесь с узкими местами (я думаю, что для написания временных результатов на диск). Я думаю, что это ваш случай (60 миллионов строк), но еще раз, я не знаю Sybase, и это зависит от многих факторов, как количество столбцов mytable и количество оперативной памяти вашего сервера и т. Д.

Вот результаты небольшого опыта, который я только что сделал:

Я запускаю на Sql-Server и PostgreSQL эти два запроса.

Запрос 1:

SELECT id, max(version) 
FROM mytable 
GROUP BY id 

Запрос 2:

SELECT id, version 
FROM 
(
    SELECT id, version, ROW_NUMBER() OVER (PARTITION BY id ORDER BY version DESC) as RN 
    FROM mytable 
) q 
WHERE q.rn = 1 

В PostgreSQL, туЬаЫе имеет 2.878.441 строк.
Запрос № 1 занимает 31.458 секунд и возвращает 1.200.146 строк.
Запрос № 2 занимает 41.787 секунд и возвращает 1.200.146 строк.

На сервере Sql mytable имеет номера 1.600.010.
Запрос № 1 занимает 6 секунд и возвращает 537,232 строки.
Запрос №2 занимает 10 секунд и возвращает 537,232 строки.

До сих пор ваш запрос всегда был быстрее. Поэтому я попробовал на больших столах.

На PostgreSQL mytable теперь имеет 5,875.134 строк.
Запрос №1 занимает 100.915 секунд и возвращает 2.796.800 строк.
Запрос № 2 занимает 98.805 секунд и возвращает 2.796.800 строк.

На сервере Sql mytable имеет 11.712.606 строк.
Запрос №1 принимает 28 мин 28 сек и возвращает 6.262.778 строк.
Запрос №2 принимает 2 мин. 39 сек. и возвращает 6.262.778 строк.

Теперь мы можем сделать предположение. В первой части этого опыта. У двух серверов достаточно памяти для обработки данных, поэтому Group By работает быстрее. Вторая часть этого эксперимента может доказать, что слишком много данных убивают производительность группы. Чтобы предотвратить узкое место, ROW_NUMBER(), похоже, делает трюк.

Критика: У меня нет большой таблицы на PostgreSQL, и у меня нет сервера Sybase.

Для этого эксперимента я использовал PostgreSQL 9.3.5 на x86_64 и SQL Server 2012 - 11.0-2100.60 (X64)

Может Nicolas этот эксперимент поможет вам.

+0

Мне тоже любопытно.IMHO «PARTITION BY» - это почти такая же работа, как и «GROUP BY», но с «MAX» он может сохранять только одно значение при потоковой передаче данных при использовании «ROW_NUMBER()» и сброса всех результаты в temp-таблице означают, что он также должен сохранять каждое значение в «памяти» для всей операции. – deroby

+0

Я сделаю некоторый ориентир на завтра, и я обновлю свой слишком быстрый ответ. – devoh

+0

Я только что проверил ваш запрос, и он не поддерживается. Неверный синтаксис рядом с ключевым словом «OVER». –

0

Функция max() не помогает оптимизатору использовать индекс. Может быть, вы должны создать индекс-функции на макс (версия):
http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc32300.1550/html/sqlug/CHDDHJIB.htm

+0

Я не знал об этой функции. Должен ли я создавать индекс по id, max (версия) или только max (версия)? –

+0

Я только что проверил, и агрегированные функции в индексе не допускаются. Он работает только с неагрегатными функциями, такими как нижний или верхний. –

 Смежные вопросы

  • Нет связанных вопросов^_^