|
|
|
"ПРАВИЛЬНЫЙ" SQL-запрос
|
|||
|---|---|---|---|
|
#18+
Пишу клиентское приложение, для которого требуется представлять данные пользователю различными способами: фильтровать данные по большому количеству параметров, группировать, сортировать большим количеством способов и т.д. Одним словом дать пользователю широкие возможности. Для решения разбил задачу на логические куски: написал функции для фильтрации данных, для проверки прав, сортировки, форматирования данных; представления для объединения с справочниками; процедуры для дополнительных нужд; различные промежуточные временные таблицы. Все в конечном итоге объеденил в хронимой процедуре. И все работает, но... Как разработчик, видимо, преувеличил возможности SQL-сервера по оптимизации. Он не стал разбирать мой сложный синтаксис запроса с целью представления его в более элегантный (пусть и длинный) и значительно более быстрый. Я провел тест на скорость, простым умножением на произвольную таблицу (так как данных у меня в таблицах еще пока очень мало - по 10-100 строк) довел результирующую выборку до 1000-50000 строк. Запросы исчислялись минутами и десятками минут. Небольшое изменение запроса позволило сократить время в 10 раз. Понял что бездарно написанный запрос может свести к минимуму все усилия сервера. Сам вопрос: На сколько я понимаю, написание запроса должно подчинятся определенным правилам, с точки зрения оптимальности. Много информации как оптимизировать сам сервер, как оптимизировать с точки зрения правильной индексации, но мало информации как оптимизировать сам запрос. Буду очень благодарен за ссылки на подобные статьи, литературу и топики. За информацию: "так можно, но так лучше". Я понимаю, что необходим опыт, но опыт других мог бы быть хорошим подспорьем. Заранее благодарен. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.11.2002, 23:05:19 |
|
||
|
"ПРАВИЛЬНЫЙ" SQL-запрос
|
|||
|---|---|---|---|
|
#18+
Может вы покажете свои запросы ? Sql сервер довольно быстро делает выборки. Может у вас I/O тормозит ? Сетка какая ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.11.2002, 10:02:56 |
|
||
|
"ПРАВИЛЬНЫЙ" SQL-запрос
|
|||
|---|---|---|---|
|
#18+
>vap Как то даже боюсь скрипт приводить. Он составит с десяток страниц (со всеми представлениями, функциями и т.п. в конечном итоге участвующих в запросе). Более того, без структуры БД будет сложно понять, что я из всего этого хочу. Вряд ли кому-либо в этом захочется разбираться. Что касается сетки, то у меня тестовый сервер MSDE на этом же компьютере. А более частные вопросы можно было бы сформулировать следующим образом: а) Приводит ли к замедлению разбивка запроса на "внешне" исполняемые куски: пользовательские функции, представления, процедуры? Или рекомендуется не разбивать запрос? б) Компилируются ли вместе с процедурой вызываемые из нее функции, представления или каждый раз для них формируется свой план исполнения? в) Замедляет ли работу использование вложенных представлений (одно View ссылается на другое, которое в свою очередь ссылается на другое и т.д. - другими словами, проектировать результирующий набор данных аналогично принципам ООП)? г) Рекомендуется ли использовать промежуточные временные таблицы? Достаточно ли понятлив сервер, чтобы не производить лишних операций ввода вывода? Что лучше: Insert Into #Temp.. или Select Into #Temp? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.11.2002, 17:31:48 |
|
||
|
"ПРАВИЛЬНЫЙ" SQL-запрос
|
|||
|---|---|---|---|
|
#18+
a) лучше разбивать очень сложные запросы... хотя когда как... б) все компилируется раздельно..... по возможности лучше обходится без функций..... т.е. если есть возможность обойтись процедурой то лучше процедура.. в) не замедляет но ,по моему, есть ограничение на вложенность.... г) все их пользуем.... ;)) select into используй аккуратно.... это удобно кнечно ... но операция относится к bulk insert.. (массовая закачка)... и иногда не журналируется.... (зависит от режима восстановления базы)... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.11.2002, 18:10:30 |
|
||
|
"ПРАВИЛЬНЫЙ" SQL-запрос
|
|||
|---|---|---|---|
|
#18+
http://www.sql-server-performance.com/transact_sql.asp ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.11.2002, 21:14:27 |
|
||
|
"ПРАВИЛЬНЫЙ" SQL-запрос
|
|||
|---|---|---|---|
|
#18+
select into я бы вообще не использовал. Разве только так - Код: plaintext 1. 2. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.11.2002, 14:47:21 |
|
||
|
"ПРАВИЛЬНЫЙ" SQL-запрос
|
|||
|---|---|---|---|
|
#18+
"Правильный" SQL запрос - это небольшой SQL-запрос. Если у Вас количество JOIN-ов в SELECT-е зашкаливает за десятку, если есть "вложенные" VIEW, если один SQL-запрос, если его распечатать, занимает больше страницы -значит он неправильный. Или модель даннных спроектирована неправильно (что более вероятно). Если у Вас одна хранимая процедура на Transact-SQL занимает больше 200 строчек - то она тоже неправильная, нужно использовать две или три хранимые процедуры. Вобщем, не приписывайте фантастических возможностей синтаксическому анализатору и оптимизатору SQL-Server-а, он ошибается даже на простых случаях. Программисты Microsoft - хорошие программисты, но не гении. От слишком сложных SQL-запросов у него едет крыша. Упростите жизнь и себе, и SQL-серверу. И не пытайтесь всё сделать на Transact-SQL, т.к. это довольно бедный и глючный инструмент программирования. Но, к счастью, существуют и клиентские средства разработки. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.11.2002, 20:05:52 |
|
||
|
"ПРАВИЛЬНЫЙ" SQL-запрос
|
|||
|---|---|---|---|
|
#18+
Ваш эксперимент мог быть неудачным, сели не обновилась статистика и/или не произошла рекомпиляция запросов, на которых основан основной запрос. > а) Приводит ли к замедлению разбивка запроса на "внешне" исполняемые куски: пользовательские функции, представления, процедуры? Или рекомендуется не разбивать запрос? Обычно разбивка ускоряет выполнение хранимых процедур, если для их выполнения (которое происходит часто) не выполняется большая часть громоздкого кода, рассованного по разным хранимым процедурам, запускающимся только при выполнении некоторых определенных условий. Для VIEW обычно это значения не имеет. Построите ли вы один VIEW сложный с подзапросами, либо несколько основанных друг на друге, не суть важно. Другое дело, что запросы с подзапросами обычно делаются там, где подзапрос отделить от запроса в принципе невозможно (из-за их связки по некоторому условию). Функции, возвращающие скалярные значения, без острой необходимости желательно не использовать. Включение подобной функции в запрос (например, в условие WHERE), может сильно тормознуть выборку - функция будет вызываться для каждой записи, а на сохранение контекста и создание нового уходит много времени. Функции, возвращающие таблицу, делятся на inline-функции и обычные. Везде, где только возможно, нужно стараться использовать inline-функции. Их планы выполнения могут сливаться с планами выполнения вызывающего запроса наиболее оптимальным образом. >б) Компилируются ли вместе с процедурой вызываемые из нее функции, представления или каждый раз для них формируется свой план исполнения? Отчасти ответ на этот вопрос дан выше. Inline-функции компилируются вместе. НЕ inline и скалярные - отдельно. View - вместе. >в) Замедляет ли работу использование вложенных представлений (одно View ссылается на другое, которое в свою очередь ссылается на другое и т.д. - другими словами, проектировать результирующий набор данных аналогично принципам ООП)? Обычно оптимизатор анализирует праны всех VIEW, чтобы построить оптимальный запрос для запроса, построенного на нескольких VIEW. Избегай использования подзапросов там, где могжно построить запрос с помощью JOIN. ВСЕМИ СИЛАМИ старайся избегать использования WHERE Something IN (...). Это вызывает страшные тормоза, если оптимизатор сам не дотумкает, как преобразовать подобный запрос в запрос с JOIN. > г) Рекомендуется ли использовать промежуточные временные таблицы? Достаточно ли понятлив сервер, чтобы не производить лишних операций ввода вывода? Использование временных таблиц приводит к компиляции скриптов, их использующих, при каждом вызове. Если объем скрипта большой, то на саму компиляцию может уходить приличное время при каждом вызове. Поэтому временные таблицы использовать нужно только в тех местах, где они без них обойтись действительно невозможно. Или там, где время выполнения скрипта заведомо выше времени компиляции. либо там, где процедура вызывается редко. > Что лучше: Insert Into #Temp.. или Select Into #Temp? Лучше или хуже, это смотря какую цель ты преследуешь. Нужно знать, что select into для некоторых recovery model могут не фиксироваться в журнале транзакций (то есть, подобные операции могут происходить НЕ в транзакции). С одной стороны, это увеличивает скорость их выполнения, с другой стороны, уменьшает надежность системы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.11.2002, 20:55:12 |
|
||
|
"ПРАВИЛЬНЫЙ" SQL-запрос
|
|||
|---|---|---|---|
|
#18+
Большое спасибо всем за проявленное внимание. 2vics хорошая ссылка, спасибо 2Oleg F Упомянутые мною представления, процедуры и функции несут строгую направленность на клиентское приложение. Перенос всей логики БД и вычислений из клиентского приложение на сервер один из акцентов на который я ориентируюсь. Цель - более легкое сопровождение и наращиваемость приложения. От того и длинные запросы. Критика такой точки зрения всегда имеет место, но взвешанная оценка всех за и против дает мне основание в принятии этого решения. Спасибо. 2Garya Спасибо за подробные и дельные советы. Проведенные мною эксперименты показали, что скалярные функции приводят к затратам большей части времени моего запроса. Также конструкцией WHERE Something IN (...) я очень часто злоупотреблял. Буду искать пути решения. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.11.2002, 00:09:49 |
|
||
|
|

start [/forum/topic.php?fid=46&gotonew=1&tid=1819085]: |
0ms |
get settings: |
8ms |
get forum list: |
14ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
43ms |
get topic data: |
9ms |
get first new msg: |
5ms |
get forum data: |
16ms |
get page messages: |
57ms |
get tp. blocked users: |
1ms |
| others: | 226ms |
| total: | 385ms |

| 0 / 0 |
