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

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

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

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

Сообщение pticelov » 12 фев 2009, 14:00

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

2 таблицы:
incalls, в которую заносится информации о пришедшем вызове (время начала, длительность, номер абонента)
outcalls, в которую заносятся исходящие вызовы (куда, длительность ожидания ответа, длительность разговора номер входящего вызова), к каждому входящему может быть несколько исходящих

первая грабель была на отчете, выводящем историю звонков, там шел цикл для всех водящих за период (один select) вывести информацию о нем и потом - обо всех его исходящих

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

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

Поэтому ключевой вопрос сейчас - кто тормозит и должно ли быть так :)

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

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

Сообщение hvlad » 12 фев 2009, 14:33

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

Tonal
Сообщения: 104
Зарегистрирован: 30 сен 2007, 13:42

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

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

По описанию явно напрашивается join по номеру для выдирания всех этих данных одним запросом.
Но для его написания таки нужно схему данных и какие именно из их нужны.

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

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

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

А ведь у меня данные в БД поступают в реальном времени, и кое что проверяется там же, 7 ms на запрос - это смертоубийство.
замечательно, просто замечательно!
кстати, вот делаю похожий запрос к employee (из employee.fdb). Время выполнения - 0 миллисекунд.
Рекомендую все-таки прислушаться к моим словам по поводу сравнения файл-сервера и клиент-сервера.
Телефонный коммутатор.
биллинговых решений на ИБ-ФБ можно насчитать штук 15, тех, которые тиражируются и продаются. У них проблем не наблюдается.

В данном топике меня несколько смущает с одной стороны грамотность вопрошающего, и с другой стороны "контроль целостности не нужен", упор на скорость MS Jet, подозрительно "немоделированное" решение задачи, и т.п. вещи. Как-то странно получается, несовместимо. Впечатление вроде как хорошо программирующий на ассемблере вдруг сел писать программы в клиент-сервере.

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

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

Сообщение pticelov » 12 фев 2009, 21:55

Tonal писал(а):По описанию явно напрашивается join по номеру для выдирания всех этих данных одним запросом.
Но для его написания таки нужно схему данных и какие именно из их нужны.
Увы - результатом этого многократного select может быть отсуствие данных. В некоторых случаях ко входному вызову исходящий с разговором может отсуствовать - клиент слушал музыку, ожидая освобождения оператора, и не дождавшись бросил трубку. Вариант с join'ом пропустит такие случаи (во всяком случае я не умею сделать такой join)

В других случаях в outcalls у нас несколько записей, соответствующих критерию. Мне нужна первая. join сделает несколько результатов и нужно будет убирать дубликаты, впрчоем, это не проблема.

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

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

Сообщение pticelov » 12 фев 2009, 22:04

kdv писал(а):
А ведь у меня данные в БД поступают в реальном времени, и кое что проверяется там же, 7 ms на запрос - это смертоубийство.
замечательно, просто замечательно!
кстати, вот делаю похожий запрос к employee (из employee.fdb). Время выполнения - 0 миллисекунд.
Рекомендую все-таки прислушаться к моим словам по поводу сравнения файл-сервера и клиент-сервера.
[/quote]

Фокус в том, что на старом проекте у меня тое было близко к нулю. Но там был firebird 1.5. Вот я и пытаюсь понять, что не так.

А как установить firebird в режиме "файл сервер", чтобы с ним можно было работать через odbc? И будут ли при этом с ним работать другие приложения (хотя бы в варианте "просто посмотреть", хотя иногда приходится и поменять что-то в БД)
Телефонный коммутатор.
биллинговых решений на ИБ-ФБ можно насчитать штук 15, тех, которые тиражируются и продаются. У них проблем не наблюдается.
1. А это не запрос не из биллинга.
2. Биллинг менее критичен к таким вещам. А у меня колцентр, у него вреальном времени надо сходить в БД, проверить кое-что по звонящему клиенту. Ну и статистический отчет, который делал 3500 запросов - это тоже не из биллинга задача.
3. Я не очень хочу сильно затачивать задачу под firebird, чтобы не оказаться в заднице при необходимости перейти на другую СУБД.
В данном топике меня несколько смущает с одной стороны грамотность вопрошающего, и с другой стороны "контроль целостности не нужен", упор на скорость MS Jet, подозрительно "немоделированное" решение задачи, и т.п. вещи. Как-то странно получается, несовместимо. Впечатление вроде как хорошо программирующий на ассемблере вдруг сел писать программы в клиент-сервере.
На ассемблере в наше время мало кто программирует, я программирую на Си. Ну а так верно, прикладняа часть у меня - это небольшая задача в рамках большого проекта, поэтому я решаю ее максимально тупо.

MS jet - это удобное решение для клиентов, которые не хотят думать ни о чем. Для тех, кому нужна большая надежность, хотел рекомендовать firebird, но вот столкнулся с тормозами там, где не ожидал.

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

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

Сообщение kdv » 13 фев 2009, 01:19

А как установить firebird в режиме "файл сервер", чтобы с ним можно было работать через odbc?
firebird никак не установить в режиме "файл сервер", потому что Firebird это клиент-сервер.
С Firebird можно работать через ODBC без проблем. На сайте есть соответствующий документ.

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

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

Сообщение pticelov » 13 фев 2009, 03:19

hvlad писал(а):
pticelov писал(а):А embedded работает через odbc? Вроде бы нет.
С какой стати ?
А вот показалось так.

Чутка напряг догадливость, вписал в dsn fbembed.dll вместо dbclient.dll, получил embedded. Время выполнения проблемного запроса - то же самое :(
pticelov писал(а):Но в любом случае, эти 7 ms - это не накладные расходы от клиент-сервер. Потому что заливка данных в БД, где так же отдельный prepared запрос выполнялся для добавления каждой строки, прекрасно добавляля больше 5000 строк в секунду, т.е. все накладные расоды вместе со временем выполнения запроса не превышали 0.5 ms.
Накладные расходы на insert и на select несколько отличаются.
А добавить можно и 20К и 50К в секунду...
Наверное. Но у меня не стояла задача оптимизировать это копирование. Оно отработало за 15 минут одиночными prepared запросами и все. Я об идее отключить индексы на время копирования данных лишь задним числом догадался. Тут оно лишь демонстрирует пример, что эти 7 ms - не накладные расходы обмена данными с сервером.

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

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

Сообщение pticelov » 13 фев 2009, 03:21

kdv писал(а):
А как установить firebird в режиме "файл сервер", чтобы с ним можно было работать через odbc?
firebird никак не установить в режиме "файл сервер", потому что Firebird это клиент-сервер.
С Firebird можно работать через ODBC без проблем. На сайте есть соответствующий документ.
Ну я подумал по тексту выше, что у него есть какой-то особый режим работы file server :)

Tonal
Сообщения: 104
Зарегистрирован: 30 сен 2007, 13:42

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

Сообщение Tonal » 13 фев 2009, 07:29

pticelov писал(а):Увы - результатом этого многократного select может быть отсуствие данных. В некоторых случаях ко входному вызову исходящий с разговором может отсуствовать...
В других случаях в outcalls у нас несколько записей, соответствующих критерию. Мне нужна первая. join сделает несколько результатов и нужно будет убирать дубликаты, впрчоем, это не проблема.
Однако left join ты описываешь. :)
Ну а чтобы только одна - можно джойнить не с самой таблицей, а с результатом группировки.
Причём это будет работать на всех вменяемых серверах (даже на jet-е).

Ещё можно это же с помощью CTE изобразить, но его ещё мало кто поддерживает.
Или на execute block, но это уже чисто FB-шное. :)

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

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

Сообщение pticelov » 13 фев 2009, 08:10

Tonal писал(а):
pticelov писал(а):Увы - результатом этого многократного select может быть отсуствие данных. В некоторых случаях ко входному вызову исходящий с разговором может отсуствовать...
В других случаях в outcalls у нас несколько записей, соответствующих критерию. Мне нужна первая. join сделает несколько результатов и нужно будет убирать дубликаты, впрчоем, это не проблема.
Однако left join ты описываешь. :)
Ну а чтобы только одна - можно джойнить не с самой таблицей, а с результатом группировки.
Причём это будет работать на всех вменяемых серверах (даже на jet-е).

Ещё можно это же с помощью CTE изобразить, но его ещё мало кто поддерживает.
Или на execute block, но это уже чисто FB-шное. :)
Ну если честно, то для задачи "чтоб была одна запись, а не несколько", я и без join не умею силами стандартного SQL сделать группировку по какому-то полю так, чтобы в результате получить значение полей у первой записи в группе, а не результат какой-то функции для полей в группе (min, max, count etc) :(

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

Tonal
Сообщения: 104
Зарегистрирован: 30 сен 2007, 13:42

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

Сообщение Tonal » 13 фев 2009, 09:56

Прочитай таки про left join - инфы море. :)
Скорее всего у тебя будет что-то в таком роде:

Код: Выделить всё

select ...
from incall ti
left join outcalls to on to.incall = ti.incall
where ...
Чтобы была одна запись, можно так, например:

Код: Выделить всё

select ...
from incall ti
left join (select incall, min(id) as id from outcalls group by incall) toid on toid.incall = ti.incall
join outcalls to on to.id = toid.id
where ...
ежели ничего не напутал. :)

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

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

Сообщение WildSery » 13 фев 2009, 10:28

Автору идти читать статью.
(А может, нужно начать с Дейта?)
И ещё, чтобы развеять твои сомнения, скажу - с SQL можно выбрать практически любую хитрожопую фигню, которую только в состоянии выдумать воспалённый разум.

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

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

Сообщение pticelov » 13 фев 2009, 15:24

Tonal писал(а):Прочитай таки про left join - инфы море. :)
ежели ничего не напутал. :)
Да, про left/right join у меня как-то мимо прошло. И впрямь может :)

Попробую вчерком интереса ради, а то мой спинной мозг пытается меня убедить, что это будет медленно работать ("медленно" по сравнению с локальным запросом без лишнего оверхеда в 7 ms н азапрос; понятно, что запрос идет по сети на другой конец света, любой тормозной запрос на сервере, но один - это лучше, чем 3500 быстрых запросов в цикле).

Впрочем, это нисколько не снимает остроту вопроса про тормоз на 7 ms. Проблемы-то разные.

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

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

Сообщение hvlad » 13 фев 2009, 15:36

pticelov писал(а):Чутка напряг догадливость, вписал в dsn fbembed.dll вместо dbclient.dll, получил embedded. Время выполнения проблемного запроса - то же самое :(
Строку коннекта покажи.
И запрос с полной статистикой выполнения.

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

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

Сообщение pticelov » 13 фев 2009, 16:31

hvlad писал(а):
pticelov писал(а):Чутка напряг догадливость, вписал в dsn fbembed.dll вместо dbclient.dll, получил embedded. Время выполнения проблемного запроса - то же самое :(
Строку коннекта покажи.
И запрос с полной статистикой выполнения.
Начал писать ответ, вставил DSN, полез для чистоты эксперимента копировать именно тот самый запрос именно из того самого места, чтобы случайно похожий не выдать, и тут обнаружил .... да-да-да, конечно, что грабли всегда прячутся в неожиданном месте :) Строка была длинная, +0 к order by id я поставил в конце, а вот в середине ...

запрос выглядел так:

select len,diallength,starttime from outcalls where len<>0 and incall=? and starttime >= ? order by id+0

как несложно заметить, к предыдущему обсуждаемому варианту добавилась еще одна проверка. Ее быстрое убивание дало разумное время, на котором embedded показал, что такое embedded:
1400 ms (как ms jet с проверкой на starttime) против 2000 ms у сервера

Правда у embedded, конечно, грабля неприятная - одно соединение к БД и все. jet позволяет несколько соединений.

после первых граблей я быстро понял, что лишние 7 ms выползли от этого сравнения по starttime, но starttime >= ?+0 не помогло

статистика и план (из flamerobin с конкретными параметрами):

35 fetches, 0 marks, 0 reads, 0 writes.
0 inserts, 0 updates, 0 deletes, 11 index, 0 seq.
Delta memory: -32 bytes.
Execute time: 00:00:00.
Script execution finished.
Preparing query: select len,diallength,starttime from outcalls where len<>0 and incall=1690132 and starttime >= '2009-02-04 02:07:27' order by id+0
Prepare time: 00:00:00.
Field #01: OUTCALLS.LEN Alias:LEN Type:INTEGER
Field #02: OUTCALLS.DIALLENGTH Alias:DIALLENGTH Type:SMALLINT
Field #03: OUTCALLS.STARTTIME Alias:STARTTIME Type:TIMESTAMP
PLAN SORT ((OUTCALLS INDEX (OUTINCALL, OUTTIME)))


Executing...
Done.

лично меня тут timestamp раздражает, это наследие старых времен, я от них давно отошел, заменив на integer, но этот проект старый.

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

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

Сообщение hvlad » 13 фев 2009, 17:16

pticelov писал(а):Правда у embedded, конечно, грабля неприятная - одно соединение к БД и все. jet позволяет несколько соединений.
В 2.5 embedded тоже позволяет несколько коннектов из разных приложений.
Много коннектов из одного приложения он позволял всегда.
pticelov писал(а):лишние 7 ms выползли от этого сравнения по starttime, но starttime >= ?+0 не помогло
starttime + 0 >= ?

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

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

Сообщение pticelov » 13 фев 2009, 18:48

hvlad писал(а):
pticelov писал(а):Правда у embedded, конечно, грабля неприятная - одно соединение к БД и все. jet позволяет несколько соединений.
В 2.5 embedded тоже позволяет несколько коннектов из разных приложений.
Много коннектов из одного приложения он позволял всегда.
Я имел в виду именно от разных. Хочется иметь возможность заглянуть в БД не прибивая приложение.

2.5 мне использовать рановато все-таки.
starttime + 0 >= ?
Конечно, помогло, но хочется понять, как обойти все оставшиеся 1001 грабель такого плана :) Может я как-то неправильно статистику обновил или еще что-то? Наверняка подстава какая-то банальная.

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

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

Сообщение Dimitry Sibiryakov » 14 фев 2009, 12:03

Да просто убей индекс по starttime к ЧМ. Нафига он тебе вообще понадобился?.. Тут тебе не акцесс, индексы от балды создавать не стоит.

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

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

Сообщение pticelov » 14 фев 2009, 18:11

Да мне этот индекс нужен - у меня полно отчетов с выборкой по starttime.

Что-то тут не так. А что - понять не могу :)

Ответить