|
|
|
Оптимизация запросов в ASA7
|
|||
|---|---|---|---|
|
#18+
Подскажите плиз как оптимизируются запросы в ASA7 ... Sybase ASA7 7.0.3 (2047) Сервер P4 - 2.8/1Gb RAM Есть вот такой запрос (на самом деле полей больше выбирается, но основной упор ИМХО надо сделать на подselect) Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. В таблице entry около миллиона записей. Под условия select попадает от 10000 до 25000 записей Во время выполнения этого запроса загрузка проца поднимается до 100% и сервер перестает отвечать на внешние раздражители... По таблице entry есть вот такие индексы: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. Поможет ли, если я создам индекс Код: plaintext 1. Код: plaintext 1. entryType <> 0 или на not entryType = 0 ? В принципе у entryType всего 3 значения может быть. И одно из них встречается намного чаще, чем два других (около 98%) Или тут ничего не поможет и ASA не умеет делать быстрые подсчеты на таблицах в миллион записей ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.09.2004, 16:50 |
|
||
|
Оптимизация запросов в ASA7
|
|||
|---|---|---|---|
|
#18+
А вот такая инструкция в семерке есть? Это чтобы сервер все-таки ворочался. Код: plaintext ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.09.2004, 16:57 |
|
||
|
Оптимизация запросов в ASA7
|
|||
|---|---|---|---|
|
#18+
Сколько записей в таблицах "subscriberPeriodData" и "Account", сколько записей в среднем обрабатывает подзапрос на каждую запись главного запроса ? И еще вопросик - поддерживает ли 7-ая версия подзапросы в секции FROM ? Код: plaintext 1. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.09.2004, 17:02 |
|
||
|
Оптимизация запросов в ASA7
|
|||
|---|---|---|---|
|
#18+
Вот наконец count по entry отработал: 1518441 записей. ASCRUS Сколько записей в таблицах "subscriberPeriodData" и "Account", сколько записей в среднем обрабатывает подзапрос на каждую запись главного запроса ? Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. Торможения начинаются при попадании в подзапрос около 10000 или более записей. ASCRUS И еще вопросик - поддерживает ли 7-ая версия подзапросы в секции FROM ? Ты вот про это ? Пример из доки: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. Рыжий кот А вот такая инструкция в семерке есть? Это чтобы сервер все-таки ворочался. SET TEMPORARY OPTION BACKGROUND_PRIORITY = ON Есть. Стоит OFF. Стоит попробовать ON поставить ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.09.2004, 17:22 |
|
||
|
Оптимизация запросов в ASA7
|
|||
|---|---|---|---|
|
#18+
1. Сделайте индекс по полям (Account_id, entryDate). Включать в индексы поле entryType смысла нет, раз там так мало значений, то ничего, кроме разбухания размера и страниц индексов добиться нельзя. 2. Ваш запрос на каждую строчку главного запроса сканирует через subquery огромную таблицу. То есть если главный запрос обхватывает 10 000 записей, то именно 10 000 раз будет идти скан таблицы entry. И тут уже без разницы, как осуществлятся сканирование - чтением таблицы или же индекса. В любом случае это будет долгая и затратная операция, так как по такому кол-ву записей СУБД не сможет эту таблицу всю вынести в кэш и постоянно будет заново читать данные с диска. Я рекомендую в раздел запроса "SELECT" включать только подзапросы, в которых участвует таблицы с малым кол-вом записей и с одной стороны для СУБД не критично все записи подзапроса вывести в кэш и вызывать хоть 10 000 раз, с другой стороны это позволяет иногда разрулить сложные части запросов и добиться правильных соединений в запросе с точки зрения оптимизатора ASA, то есть достичь лучшего плана. В Вашем случае однозначно таблица Entry должна быть перенесена в секцию FROM. Если 7-ая версия поддерживает JOIN-синтаксис, то примерно это будет выглядеть так: Код: plaintext 1. 2. 3. 4. 5. Если JOIN-ов еще нет, то можно соединить таблицы в стандарте ANSI SQL, т.е. через WHERE, используя для левостороннего соединения оператор "*=" (как точно правильно я не помню, нужно смотреть BOL). Код: plaintext 1. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.09.2004, 18:00 |
|
||
|
Оптимизация запросов в ASA7
|
|||
|---|---|---|---|
|
#18+
ASCRUS 1. Сделайте индекс по полям (Account_id, entryDate). Включать в индексы поле entryType смысла нет, раз там так мало значений, то ничего, кроме разбухания размера и страниц индексов добиться нельзя. Сделал. Вроде слегка полегчало. Насколько я понимаю сервер сам соображает, что надо использовать индекс автор 2. Ваш запрос на каждую строчку главного запроса сканирует через subquery огромную таблицу. То есть если главный запрос обхватывает 10 000 записей, то именно 10 000 раз будет идти скан таблицы entry. В любом случае это будет долгая и затратная операция, так как по такому кол-ву записей СУБД не сможет эту таблицу всю вынести в кэш и постоянно будет заново читать данные с диска. Я рекомендую в раздел запроса "SELECT" включать только подзапросы, в которых участвует таблицы с малым кол-вом записей и с одной стороны для СУБД не критично все записи подзапроса вывести в кэш и вызывать хоть 10 000 раз, с другой стороны это позволяет иногда разрулить сложные части запросов и добиться правильных соединений в запросе с точки зрения оптимизатора ASA, то есть достичь лучшего плана. В Вашем случае однозначно таблица Entry должна быть перенесена в секцию FROM. Если 7-ая версия поддерживает JOIN-синтаксис, то примерно это будет выглядеть так: SELECT spd.ID, spd.subscriberID, eventSum = IsNull(Sum(e.Qty), 0) FROM subscriberPeriodData spd INNER JOIN Account a ON spd.subscriberID = a.SubscriberID LEFT JOIN entry e ON e.accountID=a.ID AND (e.entryDate BETWEEN spd.periodStart AND spd.PeriodEnd) AND e.entryType > 0 Если JOIN-ов еще нет, то можно соединить таблицы в стандарте ANSI SQL, т.е. через WHERE, используя для левостороннего соединения оператор "*=" (как точно правильно я не помню, нужно смотреть BOL). Главный запрос охватывает от 12 до 30 записей. И у меня в боевом запросе два подзапроса: один берет записи с entryType>0, а другой с entryType=0 Т.е должно будет выглядеть примерно так ? Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.09.2004, 18:28 |
|
||
|
Оптимизация запросов в ASA7
|
|||
|---|---|---|---|
|
#18+
Я бы посоветовал бы вытащить поле где имется подзапрос во внешнюю процедуру, т.е. нечто select spd.ID, spd.subscriberID, eventSum(a.ID,spd.periodStart,spd.PeriodEnd) from subscriberPeriodData spd, Account a where spd.subscriberID = a.SubscriberID functon eventSum(in ID,in periodStart,in PeriodEnd) return .... begin declare a ...; a = isnull((select sum(Qty) from entry where accountID=ID and (entryDate between spd.periodStart and spd.PeriodEnd),1 ) and entryType > 0 ..... end ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.09.2004, 20:04 |
|
||
|
Оптимизация запросов в ASA7
|
|||
|---|---|---|---|
|
#18+
авторСделал. Вроде слегка полегчало. Насколько я понимаю сервер сам соображает, что надо использовать индекс Угу, обязательно должен. Индекс этот для него в самый раз будет. авторГлавный запрос охватывает от 12 до 30 записей. И у меня в боевом запросе два подзапроса: один берет записи с entryType>0, а другой с entryType=0 Т.е должно будет выглядеть примерно так ? Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. Гм - ну зачем же так сложно ? :) 1. Дважды сканировать таблицу с 1,5 миллионом записей явно не стоит, особенно, если можно без этого обойтись. 2. В Вашем запросе "entry e1" можно смело связать с "Account a" и выбросить из связки зачем то дублирующуюся таблицу "Account a" (или это просто опечатка ?) 3. Без GROUP BY работать не будет, у нас же все таки аггрегатный запрос. 3. Раз уж нам надо посчитать 2 суммы, зависящие просто от условия при подсчете, давайте именно так и делать: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. Далее если так "чисто случайно" в таблице Entry всегда accountID имеет аналогичную запись в Account (то есть установлен Foreign Key между этими таблицами), то можно вообще вместо LEFT JOIN поставить INNER JOIN, получить чистое прямое соединение, и наслаждаться скоростью запроса :) Sergey OrlovЯ бы посоветовал бы вытащить поле где имется подзапрос во внешнюю процедуру А вот этого делать не стоит вообще никогда, кроме случаев, когда функции передается константа или переменная. Сделав такое мы получим: 1. Все равно функция будет вызываться на каждую строчку главного запроса, что ничем не отличается от того же subquery. 2. Функция в отличие даже от subquery никогда не войдет в план запроса, откуда оптимизатору знать, чего там она и как делает. Не стоит забывать, что для функций оптимизатор предполагает, что они служат для вычислений и преобразований, а не в качестве средства получения запроса с 1,5 миллионной таблицы. 3. Функцию еще нужно каждый раз вызвать и выполнить, что тоже дополнительно занимает время и даже ресурсы, так как в функции обьявляются и удаляются сборщиком мусора переменные. ... и еще много много другого, что можно долго перечислять ... Так что я думаю использовать в запросах функции нужно только тогда, когда они действительно нужны. Даже если можно обойтись средствами WatcomSQL, лучше обойтись ими (тот же IF END IF), чем писать универсальную функцию, все назначение которой - сократить чуть чуть кода при написании скриптов. Сократить то можно, вот только производительность сокращается так же, а это для БД не приемлемо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.09.2004, 02:09 |
|
||
|
Оптимизация запросов в ASA7
|
|||
|---|---|---|---|
|
#18+
авторГлавный запрос охватывает от 12 до 30 записей. И у меня в боевом запросе два подзапроса: один берет записи с entryType>0, а другой с entryType=0 Т.е должно будет выглядеть примерно так ? Sergey OrlovЯ бы посоветовал бы вытащить поле где имется подзапрос во внешнюю процедуру А вот этого делать не стоит вообще никогда, кроме случаев, когда функции передается константа или переменная. Сделав такое мы получим: 1. Все равно функция будет вызываться на каждую строчку главного запроса, что ничем не отличается от того же subquery. 2. Функция в отличие даже от subquery никогда не войдет в план запроса, откуда оптимизатору знать, чего там она и как делает. Не стоит забывать, что для функций оптимизатор предполагает, что они служат для вычислений и преобразований, а не в качестве средства получения запроса с 1,5 миллионной таблицы. 3. Функцию еще нужно каждый раз вызвать и выполнить, что тоже дополнительно занимает время и даже ресурсы, так как в функции обьявляются и удаляются сборщиком мусора переменные. ... и еще много много другого, что можно долго перечислять ... Так что я думаю использовать в запросах функции нужно только тогда, когда они действительно нужны. Даже если можно обойтись средствами WatcomSQL, лучше обойтись ими (тот же IF END IF), чем писать универсальную функцию, все назначение которой - сократить чуть чуть кода при написании скриптов. Сократить то можно, вот только производительность сокращается так же, а это для БД не приемлемо. Но обрати внимание, что в основном запросе данное поле вычисляемое, да в план запроса функция не войдет, но в оптимизировать ее одну легче, и второе основной план запроса 10-30 записей, т.е. вызвать функцию надо всего 10-30 раз ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.09.2004, 10:35 |
|
||
|
Оптимизация запросов в ASA7
|
|||
|---|---|---|---|
|
#18+
авторНо обрати внимание, что в основном запросе данное поле вычисляемое, да в план запроса функция не войдет, но в оптимизировать ее одну легче, и второе основной план запроса 10-30 записей, т.е. вызвать функцию надо всего 10-30 раз Ну как оказалось не 10-30 раз, а 20-60, так как автор одновременно считает 2 суммы по разным условиям (мой последний вариант запроса делает это один раз). Во вторых есть один ньюанс - без функции мой запрос будет входить в главный план запроса и соотвествующе по плану индекс и таблицы будет последовательно сканироваться один раз, т.е. за один проход. В Вашем случае что функция, что использование Subquery означает сканирование этой довольно таки большой таблицы для каждой записи главного запроса, причем каждый раз с корневой страницы индекса. Еестественно будет медленнее. P.S. На практике часто оказывается, что с функциями или subquery запросы выполняются быстрее, чем с разворачиванием всего запроса в корневой план (то есть секцию FROM). Но нельзя это воспринимать как аксиому. Дело в том, что если оптимизатор не смог правильно и оптимально связать таблицы в плане, то он может построить не эффективный и тормозной план запроса. В случае же с функциями уже изначально план запроса получается меньше и шансов, что оптимизатор соединит все правильно как в главном, так и запросе функции, соотвествующе больше. Однако это не означает, что применение функций выгодней, чем написание большого запроса. Это только означает, что в запросе нужно переписать соединения таблиц, достроить нужные индексы, обьединить часть мелких таблиц во времянки - в общем добиться оптимального и красивого плана запроса и использование функций и subquery по скорости выполнения, особенно при дальнейшем росте данных окажутся далеко сзади. Код: plaintext 1. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.09.2004, 13:01 |
|
||
|
Оптимизация запросов в ASA7
|
|||
|---|---|---|---|
|
#18+
Огромное спасибо за помощь. В принципе мой опыт работы с SQL ограничивается MySQL, и в общем-то я первый раз сталкиваюсь с оптимизацией запроса по базам с миллионами записей... Про запрос с IF я как-то не сообразил ;) Самая большая проблема - это то, что база-то написана не мной. Я ее пользователь/администратор, вот и приходиться практически наощупь в ней копаться и пытатся оптимизировать. Вот такой запрос был: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. Попробуем его в деле. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.09.2004, 14:27 |
|
||
|
|

start [/forum/topic.php?fid=55&msg=32691291&tid=2014228]: |
0ms |
get settings: |
9ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
42ms |
get topic data: |
13ms |
get forum data: |
3ms |
get page messages: |
130ms |
get tp. blocked users: |
2ms |
| others: | 233ms |
| total: | 454ms |

| 0 / 0 |

Извините, этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
... ля, ля, ля ...