Страница 1 из 5
Время выполнения запроса
Добавлено: 10 фев 2009, 20:15
pticelov
Перенес базу в одном из проектов с Access на Firebird 2.1.1 и столькнулся с непонятными мне тормозами, там где не тормозил Access, и где и тормозить-то нечему.
простейший prepared запрос
select CallTo,UserID,Len,Unsuccess,DialLength,DiscReason,StartTime from outcalls where incall=? order by id
возвращающий от 0 до 10 записей, требует 250-300 ms на каждое выполнение.
Таблица такая:
CREATE TABLE outcalls(ID INTEGER, INCALL INTEGER, CallTo CHAR(20), UserID INTEGER, StartTime timestamp, Len INTEGER, Unsuccess SMALLINT, DialLength SMALLINT, DiscReason SMALLINT)
К ней есть индексы:
CREATE UNIQUE INDEX OUTCALLS_ID ON outcalls(ID)
CREATE DESCENDING INDEX OUTCALLS_ID_D ON outcalls(ID)
CREATE INDEX outincall ON outcalls(INCALL)
CREATE INDEX outtime ON outcalls(StartTime)
CREATE INDEX outuser ON outcalls(UserID)
если я убираю order by - тормоза уходят
если я запрещаю индекс OUTCALLS_ID - тормоза уходят
откуда тормоза - просто не понимаю
Re: Время выполнения запроса
Добавлено: 10 фев 2009, 21:24
hvlad
Статистику индексную обновлял ? План и статистику выполнения покажи.
order by id + 0 тебе поможет, но нужно разобраться почему оно само не смогло
Re: Время выполнения запроса
Добавлено: 10 фев 2009, 22:42
pticelov
Статистику обновил первым делом
Preparing query: select CallTo,UserID,Len,Unsuccess,DialLength,DiscReason,StartTime from outcalls where incall=1690114 order by id
Prepare time: 00:00:00.
PLAN (OUTCALLS ORDER OUTCALLS_ID INDEX (OUTINCALL))
Executing...
Done.
2431 fetches, 0 marks, 0 reads, 0 writes.
0 inserts, 0 updates, 0 deletes, 11 index, 0 seq.
Delta memory: -76 bytes.
Execute time: 00:00:00.
Script execution finished.
Re: Время выполнения запроса
Добавлено: 10 фев 2009, 22:50
hvlad
OUTCALLS ORDER OUTCALLS_ID тут мешает.
Сделай ORDER BY ID + 0
Re: Время выполнения запроса
Добавлено: 10 фев 2009, 23:30
pticelov
Гммм ...
Но теоретически у меня там может оказаться и 500 записей. Что тогда будет из-за order by?
Re: Время выполнения запроса
Добавлено: 11 фев 2009, 02:01
kdv
кстати, а почему unique а не primary key?
Re: Время выполнения запроса
Добавлено: 11 фев 2009, 02:20
pticelov
Все печально ...
250 ms на запрос мы победили ... Я на секунду расслабился ... правда общее время формирования отчета, в котором он использовался, все-таки увеличилось на 1.5 раза по сравнению с вариантом с драйвером access, но все-таки это было благопристойно. Зато другие отчеты ускорились примерно так же ... Но тут руки дошли до еще одного отчета, где такой же нехороший запрос использовался для сбора статистики по 3500 звонков (вызывался 3500 раз).
Оптимизированная версия отчета (без этого нехорошего запроса) формировалась 750 ms. Приемлимый результат (access чуть быстрее - 600-625, но это не критично). Отключаю оптимизацию и нехороший запрос начинает использоваться ... aceess 1300 ms (3500 нехороших запросов), firebird - 31000 ms. Нехороший запрос выполняется ~ 7 ms (иногда - дважды) и увеличивает врея выполнения в 20 раз.
Ни черта не понимаю. Запрос-то реально простой.
Re: Время выполнения запроса
Добавлено: 11 фев 2009, 02:21
pticelov
kdv писал(а):кстати, а почему unique а не primary key?
Да так исторически сложилось. Я не слишком продвинут в SQL и стараюсь использовать лишь простые вещи. А это влияет на производительность?
Кстати, в access - primary key, кажется, был.
Re: Время выполнения запроса
Добавлено: 11 фев 2009, 04:07
kdv
Да так исторически сложилось. Я не слишком продвинут в SQL и стараюсь использовать лишь простые вещи. А это влияет на производительность?
на производительность не влияет, но primary key это первичный ключ, а unique - всего-лишь альтернативный ключ, т.е. вторичный по отношению к primary key.
Re: Время выполнения запроса
Добавлено: 11 фев 2009, 10:42
pticelov
kdv писал(а):
на производительность не влияет, но primary key это первичный ключ, а unique - всего-лишь альтернативный ключ, т.е. вторичный по отношению к primary key.
Я понимаю, но контроль целостности силами сервера я не использую ни для чего, так что просто не знаю, к чему мне primary key
Re: Время выполнения запроса
Добавлено: 11 фев 2009, 11:33
WildSery
pticelov писал(а):Но теоретически у меня там может оказаться и 500 записей. Что тогда будет из-за order by?
Сортировка, начиная с 2.0 выполняется в памяти, потому весьма быстра, и 10, или 500, или 2000 - особой погоды не сделает.
pticelov писал(а):Все печально ...
Ни черта не понимаю. Запрос-то реально простой.
Оптимизирую процедуру за небольшое вознаграждение.
Если же есть конкретные вопросы, а не "почему тормозит то, на что я смотрю, и маааленький кусочек показал вам (да и то не совсем как у меня)", то можно и бесплатно помочь.
Re: Время выполнения запроса
Добавлено: 11 фев 2009, 16:43
pticelov
WildSery писал(а):
Оптимизирую процедуру за небольшое вознаграждение.
Если же есть конкретные вопросы, а не "почему тормозит то, на что я смотрю, и маааленький кусочек показал вам (да и то не совсем как у меня)", то можно и бесплатно помочь.
А что вы собираетесь оптимизировать? Процедуру на абсолютно незнакомом Вам языке программирования, делающую быстро кучу своих дел, и имеющую единственное узкое место - этот запрос, который выполняется через ODBC? Весь прочий код там выполняется за разумное время, тормозит лишь этот запрос, хотя тормозить там просто нечему - запрос-то простой.
Я, конечно, могу всегда преписать принципиально код, который вызвыает этот запрос, сделав вместо 3500 запросов один, который всосет с запасом все потенциально подходящие записи в память и дальше я буду с массивом работать, но это - из разряда секса стоя в гамаке и для таких решений надо сначала понимать, почему это так себя ведет и поставить крест на нормальной работе с firebird.
На самом деле у меня сейчас есть вариант, не использующий это запрос, но мне-то надо понять, что происходит с ним, чтобы дальше нормально пользоваться firebird'ом
Re: Время выполнения запроса
Добавлено: 11 фев 2009, 21:35
kdv
то запрос, теперь выясняется, что это оказывается запрос в процедуре. Потом еще выяснится, что запрос выполняется через Execute statement?
Я понимаю, но контроль целостности силами сервера я не использую ни для чего, так что просто не знаю, к чему мне primary key
убил напрочь. зачем тогда unique ? Вообще феерическая дискуссия. "У меня тут и запрос и процедура и ОДБЦ, и незнакомый язык процедур, и работает медленно (300 миллисекунд). Я хочу чтобы было быстрее, но оптимизировать мне это не надо."
Re: Время выполнения запроса
Добавлено: 12 фев 2009, 01:49
pticelov
kdv писал(а):то запрос, теперь выясняется, что это оказывается запрос в процедуре. Потом еще выяснится, что запрос выполняется через Execute statement?
Гммм ... Вы подумали о процедурах в SQL? Нет, слово "процедура" не от туда. Замените на "кусок кода на незнакомом Вам языке программирования"
Запрос выполняется через SQLExecute(), я же сказал - ODBC и prepared запрос.
kdv писал(а):
Я понимаю, но контроль целостности силами сервера я не использую ни для чего, так что просто не знаю, к чему мне primary key
убил напрочь. зачем тогда unique ?
А winsql подставил, когда DDL сгенерил для имеющейся базы. Когда 3 года назад этот проект делал, это была моя первая попытка работать с SQL. Поставил primary key. Потом, когда сгенерил DDL в winsql для переноса в firebird, он все первичные ключи превратил в unique, ну я и оставил как есть. Вреда в нем нет. Впрочем пользы - тоже.
Вообще феерическая дискуссия. "У меня тут и запрос и процедура и ОДБЦ, и незнакомый язык процедур, и работает медленно (300 миллисекунд). Я хочу чтобы было быстрее, но оптимизировать мне это не надо."
Это Вам так хочется это прочитать.
У меня тут программа, кусок которой написан на незнакомом вопрошающему товарищу языке программирования (встроенный язык этой системы). Программа работает с SQL через ODBC. Где-то там в формировании отчета используется prepared запрос. С первого захода он работал 250 ms, что было нереально много. Разобрались. Потом выяснилось, что даже с "order by id+0" он все равно работает не быстро - порядка 7 ms против долей миллесекунды при работе с той же БД через MS JET, что приводит к разрастанию времени выполнения моего кода до 30 s против 1.5 с jet'ом при обработке небольшого набора данных.
Оптимизация программы путем выкидывания этого запроса - это не решение данной проблемы. Я все-таки хочу понять, кто тормозит и убрать источник тормозов, а не хитро обойти тормоз, оставив себе проблему ну другой раз.
Re: Время выполнения запроса
Добавлено: 12 фев 2009, 02:02
kdv
работает не быстро - порядка 7 ms против долей миллесекунды при работе с той же БД через MS JET
под MS Jet имеется в виду Access? Если да, то я Вас огорчу - практически любой файловый движок в однопользовательском режиме работает быстрее, чем любой сервер SQL, тоже в однопользовательском режиме.
Re: Время выполнения запроса
Добавлено: 12 фев 2009, 02:11
pticelov
kdv писал(а):работает не быстро - порядка 7 ms против долей миллесекунды при работе с той же БД через MS JET
под MS Jet имеется в виду Access? Если да, то я Вас огорчу - практически любой файловый движок в однопользовательском режиме работает быстрее, чем любой сервер SQL, тоже в однопользовательском режиме.
Я сначала писал Access, но потом решил писать правильно, чтобы не путать народ - jet через odbc из приложения, написанного на Си.
режим многопользовательский, или я не понимаю о чем речь

На всякий случай: с БД отдновременно могут работать разные приложения
Re: Время выполнения запроса
Добавлено: 12 фев 2009, 10:34
kdv
Я сначала писал Access, но потом решил писать правильно, чтобы не путать народ - jet через odbc из приложения, написанного на Си.
экакая витиеватость. Си, дельфи - какая разница? Что под Jet - база MDB (Access) ?
режим многопользовательский, или я не понимаю о чем речь

На всякий случай: с БД отдновременно могут работать разные приложения
могут, это понятно. Вопрос в том, как проводится тест - запрос выполняется "доли миллисекунды" при работе 50ти пользователей?
Я не могу понять, почему Вас удивляет разница в скорости между файл-сервером и клиент-сервером. Вы же пытаетесь сравнить несравнимое. Сравните Jet с Ораклом и MS SQL в той же ситуации, например.
Re: Время выполнения запроса
Добавлено: 12 фев 2009, 10:40
hvlad
pticelov писал(а):У меня тут программа, кусок которой написан на незнакомом вопрошающему товарищу языке программирования (встроенный язык этой системы). Программа работает с SQL через ODBC. Где-то там в формировании отчета используется prepared запрос. С первого захода он работал 250 ms, что было нереально много. Разобрались. Потом выяснилось, что даже с "order by id+0" он все равно работает не быстро - порядка 7 ms против долей миллесекунды при работе с той же БД через MS JET, что приводит к разрастанию времени выполнения моего кода до 30 s против 1.5 с jet'ом при обработке небольшого набора данных.
Это клиент-сервер, тут другие подходы и выполнение 3500 раз даже отпрепаренного запроса просто не может быть моментальным, ибо данные гоняются через сетевой слой туда-сюда 3500 раз.
Хочется сравнения "в лоб" - возьми embedded.
Хочется как правильно - или выноси обработку на сервер, или избавляйся от 3500 вызовов
Re: Время выполнения запроса
Добавлено: 12 фев 2009, 12:15
WildSery
hvlad писал(а):Хочется как правильно - или выноси обработку на сервер, или избавляйся от 3500 вызовов
+1.
Нигде в здавом уме применять 3500 вызовов одного запроса мне и в голову не придёт (кроме закачки данных в биллинге, например, но это не селективный).
Пишется процедура, которая делает те же операции, либо возвращается результат сразу всех 3500 вызовов, и обрабатывается по одному в цикле, если с ними что-то в клиенте нужно делать.
Если расскажешь в двух словах, что делается, возьмусь посоветовать что-нибудь путное.
Re: Время выполнения запроса
Добавлено: 12 фев 2009, 13:52
pticelov
hvlad писал(а):Это клиент-сервер, тут другие подходы и выполнение 3500 раз даже отпрепаренного запроса просто не может быть моментальным, ибо данные гоняются через сетевой слой туда-сюда 3500 раз.
Хочется сравнения "в лоб" - возьми embedded.
Хочется как правильно - или выноси обработку на сервер, или избавляйся от 3500 вызовов
А embedded работает через odbc? Вроде бы нет. Но в любом случае, эти 7 ms - это не накладные расходы от клиент-сервер. Потому что заливка данных в БД, где так же отдельный prepared запрос выполнялся для добавления каждой строки, прекрасно добавляля больше 5000 строк в секунду, т.е. все накладные расоды вместе со временем выполнения запроса не превышали 0.5 ms.
У меня был еще один проект, в котором на этапе конвертирования данных при заливку в БД выполнялись поиски по куче таблиц (словари для фамилии, имени, отчества, городов, улиц, проверка на наличие дублей записей по нескольким параметрам), и firebird справлялся с несколькими сотнями добавлений в секунду, так что на весь кошмар из примерно десятка запросов уходило меньше 10 ms. А тут - 7 ms на один запрос.
И ключевой вопрос не в том, как обойти тормоз, а в том, как его убрать. А ведь у меня данные в БД поступают в реальном времени, и кое что проверяется там же, 7 ms на запрос - это смертоубийство.