Время выполнения запроса

Модераторы: kdv, CyberMax

pticelov
Сообщения: 95
Зарегистрирован: 28 дек 2005, 22:52

Время выполнения запроса

Сообщение pticelov » 10 фев 2009, 20:15

Перенес базу в одном из проектов с 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 - тормоза уходят

откуда тормоза - просто не понимаю

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Re: Время выполнения запроса

Сообщение hvlad » 10 фев 2009, 21:24

Статистику индексную обновлял ? План и статистику выполнения покажи.
order by id + 0 тебе поможет, но нужно разобраться почему оно само не смогло

pticelov
Сообщения: 95
Зарегистрирован: 28 дек 2005, 22:52

Re: Время выполнения запроса

Сообщение pticelov » 10 фев 2009, 22:42

Статистику обновил первым делом

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.

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Re: Время выполнения запроса

Сообщение hvlad » 10 фев 2009, 22:50

OUTCALLS ORDER OUTCALLS_ID тут мешает.
Сделай ORDER BY ID + 0

pticelov
Сообщения: 95
Зарегистрирован: 28 дек 2005, 22:52

Re: Время выполнения запроса

Сообщение pticelov » 10 фев 2009, 23:30

Гммм ...

Но теоретически у меня там может оказаться и 500 записей. Что тогда будет из-за order by?

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: Время выполнения запроса

Сообщение kdv » 11 фев 2009, 02:01

кстати, а почему unique а не primary key?

pticelov
Сообщения: 95
Зарегистрирован: 28 дек 2005, 22:52

Re: Время выполнения запроса

Сообщение pticelov » 11 фев 2009, 02:20

Все печально ...

250 ms на запрос мы победили ... Я на секунду расслабился ... правда общее время формирования отчета, в котором он использовался, все-таки увеличилось на 1.5 раза по сравнению с вариантом с драйвером access, но все-таки это было благопристойно. Зато другие отчеты ускорились примерно так же ... Но тут руки дошли до еще одного отчета, где такой же нехороший запрос использовался для сбора статистики по 3500 звонков (вызывался 3500 раз).

Оптимизированная версия отчета (без этого нехорошего запроса) формировалась 750 ms. Приемлимый результат (access чуть быстрее - 600-625, но это не критично). Отключаю оптимизацию и нехороший запрос начинает использоваться ... aceess 1300 ms (3500 нехороших запросов), firebird - 31000 ms. Нехороший запрос выполняется ~ 7 ms (иногда - дважды) и увеличивает врея выполнения в 20 раз.

Ни черта не понимаю. Запрос-то реально простой.

pticelov
Сообщения: 95
Зарегистрирован: 28 дек 2005, 22:52

Re: Время выполнения запроса

Сообщение pticelov » 11 фев 2009, 02:21

kdv писал(а):кстати, а почему unique а не primary key?
Да так исторически сложилось. Я не слишком продвинут в SQL и стараюсь использовать лишь простые вещи. А это влияет на производительность?

Кстати, в access - primary key, кажется, был.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: Время выполнения запроса

Сообщение kdv » 11 фев 2009, 04:07

Да так исторически сложилось. Я не слишком продвинут в SQL и стараюсь использовать лишь простые вещи. А это влияет на производительность?
на производительность не влияет, но primary key это первичный ключ, а unique - всего-лишь альтернативный ключ, т.е. вторичный по отношению к primary key.

pticelov
Сообщения: 95
Зарегистрирован: 28 дек 2005, 22:52

Re: Время выполнения запроса

Сообщение pticelov » 11 фев 2009, 10:42

kdv писал(а): на производительность не влияет, но primary key это первичный ключ, а unique - всего-лишь альтернативный ключ, т.е. вторичный по отношению к primary key.
Я понимаю, но контроль целостности силами сервера я не использую ни для чего, так что просто не знаю, к чему мне primary key

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Re: Время выполнения запроса

Сообщение WildSery » 11 фев 2009, 11:33

pticelov писал(а):Но теоретически у меня там может оказаться и 500 записей. Что тогда будет из-за order by?
Сортировка, начиная с 2.0 выполняется в памяти, потому весьма быстра, и 10, или 500, или 2000 - особой погоды не сделает.
pticelov писал(а):Все печально ...
Ни черта не понимаю. Запрос-то реально простой.
Оптимизирую процедуру за небольшое вознаграждение.
Если же есть конкретные вопросы, а не "почему тормозит то, на что я смотрю, и маааленький кусочек показал вам (да и то не совсем как у меня)", то можно и бесплатно помочь.

pticelov
Сообщения: 95
Зарегистрирован: 28 дек 2005, 22:52

Re: Время выполнения запроса

Сообщение pticelov » 11 фев 2009, 16:43

WildSery писал(а): Оптимизирую процедуру за небольшое вознаграждение.
Если же есть конкретные вопросы, а не "почему тормозит то, на что я смотрю, и маааленький кусочек показал вам (да и то не совсем как у меня)", то можно и бесплатно помочь.
А что вы собираетесь оптимизировать? Процедуру на абсолютно незнакомом Вам языке программирования, делающую быстро кучу своих дел, и имеющую единственное узкое место - этот запрос, который выполняется через ODBC? Весь прочий код там выполняется за разумное время, тормозит лишь этот запрос, хотя тормозить там просто нечему - запрос-то простой.

Я, конечно, могу всегда преписать принципиально код, который вызвыает этот запрос, сделав вместо 3500 запросов один, который всосет с запасом все потенциально подходящие записи в память и дальше я буду с массивом работать, но это - из разряда секса стоя в гамаке и для таких решений надо сначала понимать, почему это так себя ведет и поставить крест на нормальной работе с firebird.

На самом деле у меня сейчас есть вариант, не использующий это запрос, но мне-то надо понять, что происходит с ним, чтобы дальше нормально пользоваться firebird'ом

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: Время выполнения запроса

Сообщение kdv » 11 фев 2009, 21:35

то запрос, теперь выясняется, что это оказывается запрос в процедуре. Потом еще выяснится, что запрос выполняется через Execute statement?
Я понимаю, но контроль целостности силами сервера я не использую ни для чего, так что просто не знаю, к чему мне primary key
убил напрочь. зачем тогда unique ? Вообще феерическая дискуссия. "У меня тут и запрос и процедура и ОДБЦ, и незнакомый язык процедур, и работает медленно (300 миллисекунд). Я хочу чтобы было быстрее, но оптимизировать мне это не надо."

pticelov
Сообщения: 95
Зарегистрирован: 28 дек 2005, 22:52

Re: Время выполнения запроса

Сообщение pticelov » 12 фев 2009, 01:49

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'ом при обработке небольшого набора данных.

Оптимизация программы путем выкидывания этого запроса - это не решение данной проблемы. Я все-таки хочу понять, кто тормозит и убрать источник тормозов, а не хитро обойти тормоз, оставив себе проблему ну другой раз.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: Время выполнения запроса

Сообщение kdv » 12 фев 2009, 02:02

работает не быстро - порядка 7 ms против долей миллесекунды при работе с той же БД через MS JET
под MS Jet имеется в виду Access? Если да, то я Вас огорчу - практически любой файловый движок в однопользовательском режиме работает быстрее, чем любой сервер SQL, тоже в однопользовательском режиме.

pticelov
Сообщения: 95
Зарегистрирован: 28 дек 2005, 22:52

Re: Время выполнения запроса

Сообщение pticelov » 12 фев 2009, 02:11

kdv писал(а):
работает не быстро - порядка 7 ms против долей миллесекунды при работе с той же БД через MS JET
под MS Jet имеется в виду Access? Если да, то я Вас огорчу - практически любой файловый движок в однопользовательском режиме работает быстрее, чем любой сервер SQL, тоже в однопользовательском режиме.
Я сначала писал Access, но потом решил писать правильно, чтобы не путать народ - jet через odbc из приложения, написанного на Си.

режим многопользовательский, или я не понимаю о чем речь :) На всякий случай: с БД отдновременно могут работать разные приложения

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: Время выполнения запроса

Сообщение kdv » 12 фев 2009, 10:34

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

Я не могу понять, почему Вас удивляет разница в скорости между файл-сервером и клиент-сервером. Вы же пытаетесь сравнить несравнимое. Сравните Jet с Ораклом и MS SQL в той же ситуации, например.

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Re: Время выполнения запроса

Сообщение hvlad » 12 фев 2009, 10:40

pticelov писал(а):У меня тут программа, кусок которой написан на незнакомом вопрошающему товарищу языке программирования (встроенный язык этой системы). Программа работает с SQL через ODBC. Где-то там в формировании отчета используется prepared запрос. С первого захода он работал 250 ms, что было нереально много. Разобрались. Потом выяснилось, что даже с "order by id+0" он все равно работает не быстро - порядка 7 ms против долей миллесекунды при работе с той же БД через MS JET, что приводит к разрастанию времени выполнения моего кода до 30 s против 1.5 с jet'ом при обработке небольшого набора данных.
Это клиент-сервер, тут другие подходы и выполнение 3500 раз даже отпрепаренного запроса просто не может быть моментальным, ибо данные гоняются через сетевой слой туда-сюда 3500 раз.
Хочется сравнения "в лоб" - возьми embedded.
Хочется как правильно - или выноси обработку на сервер, или избавляйся от 3500 вызовов

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Re: Время выполнения запроса

Сообщение WildSery » 12 фев 2009, 12:15

hvlad писал(а):Хочется как правильно - или выноси обработку на сервер, или избавляйся от 3500 вызовов
+1.
Нигде в здавом уме применять 3500 вызовов одного запроса мне и в голову не придёт (кроме закачки данных в биллинге, например, но это не селективный).
Пишется процедура, которая делает те же операции, либо возвращается результат сразу всех 3500 вызовов, и обрабатывается по одному в цикле, если с ними что-то в клиенте нужно делать.
Если расскажешь в двух словах, что делается, возьмусь посоветовать что-нибудь путное.

pticelov
Сообщения: 95
Зарегистрирован: 28 дек 2005, 22:52

Re: Время выполнения запроса

Сообщение pticelov » 12 фев 2009, 13:52

hvlad писал(а):Это клиент-сервер, тут другие подходы и выполнение 3500 раз даже отпрепаренного запроса просто не может быть моментальным, ибо данные гоняются через сетевой слой туда-сюда 3500 раз.
Хочется сравнения "в лоб" - возьми embedded.
Хочется как правильно - или выноси обработку на сервер, или избавляйся от 3500 вызовов
А embedded работает через odbc? Вроде бы нет. Но в любом случае, эти 7 ms - это не накладные расходы от клиент-сервер. Потому что заливка данных в БД, где так же отдельный prepared запрос выполнялся для добавления каждой строки, прекрасно добавляля больше 5000 строк в секунду, т.е. все накладные расоды вместе со временем выполнения запроса не превышали 0.5 ms.

У меня был еще один проект, в котором на этапе конвертирования данных при заливку в БД выполнялись поиски по куче таблиц (словари для фамилии, имени, отчества, городов, улиц, проверка на наличие дублей записей по нескольким параметрам), и firebird справлялся с несколькими сотнями добавлений в секунду, так что на весь кошмар из примерно десятка запросов уходило меньше 10 ms. А тут - 7 ms на один запрос.

И ключевой вопрос не в том, как обойти тормоз, а в том, как его убрать. А ведь у меня данные в БД поступают в реальном времени, и кое что проверяется там же, 7 ms на запрос - это смертоубийство.

Ответить