Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
Есть такой запрос: Код: plaintext 1. 2. Нужен он для того, чтоб потом можно было посчитать пик одновременных звонков. Вопрос в том как создать под это дело индекс, так чтоб ускорить этот запрос. Пока пытался сделать вот что: Код: plaintext 1. 2. 3. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.10.2008, 18:34 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
можно ли вместо указанного вами использовать запрос, который не выбирает соединения, приходящиеся на границы интервала? connect_time>='20080901_000000' AND disconnect_time<='20080930_235959' тогда, учитывая что connect_time<=disconnect_time, можно будет добавить в запрос дополнительные условия для ускорения: disconnect_time>='20080901_000000' AND connect_time<='20080930_235959' для такого запроса может использоваться индекс, показывайте EXPLAIN ANALYZE. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.10.2008, 10:07 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
Во первых, снеси этот индекс и попробуй по очереди: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. Во-вторых: есть ли какое-то максимальное время звонка? Допустим это 12часов, и есть индекс по (connect_time, disconnect_time), тогда запрос приобретает вид: Код: plaintext 1. 2. 3. 4. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.10.2008, 10:08 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
LeXa NalBatможно ли вместо указанного вами использовать запрос, который не выбирает соединения, приходящиеся на границы интервала? connect_time>='20080901_000000' AND disconnect_time<='20080930_235959' тогда, учитывая что connect_time<=disconnect_time, можно будет добавить в запрос дополнительные условия для ускорения: disconnect_time>='20080901_000000' AND connect_time<='20080930_235959' К сожалению нельзя. Смысл посчитать максимальное количество одновременных звонков на промежутке. В том числе и тех, которые уже были установлены в это время. Поэтому надо брать именно такой отрезок или я чего-то не понимаю. LeXa NalBatдля такого запроса может использоваться индекс, показывайте EXPLAIN ANALYZE.Тупо проход по файлу без индекса. Чистый Explain дает вот что: Код: plaintext 1. 2. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.10.2008, 12:05 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
Сейчас попробовал сделать вот такой индекс: Код: plaintext 1. 2. 3. Код: plaintext 1. 2. Код: plaintext 1. 2. 3. 4. 5. И кстати, может имеет смысл сделать хранимую процедуру и там с помощью курсоров чего-нибудь добиться? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.10.2008, 12:34 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
WarstoneСмысл посчитать максимальное количество одновременных звонков на промежутке. В том числе и тех, которые уже были установлены в это время. Поэтому надо брать именно такой отрезок или я чего-то не понимаю.но у вас в сентябрьский интервал войдут 1) звонки, начавшиеся раньше сентября и 2) звонки, закончившиеся позже сентября. при этом звонки 1 также войдут в августовский интервал, а звонки 2 - в октябрьский. то есть пограничные звонки вы проанализируете два раза. поэтому правильнее в каждый месяц включть одну границу - например звонки, начавшиеся раньше. соответствующий запрос будет использовать индекс, условие для него: disconnect_time BETWEEN '20080901_000000' AND '20080930_235959'. WarstoneСейчас попробовал сделать вот такой индекс: ... (disconnect_time, elapsed_time, (connect_time>0)) -> Bitmap Index Scan on mera_traffic_connect_time2 (cost=0.00..62030.69 rows=1003105 width=0) (actual time=3512.238..3512.238 rows=868195 loops=1) Index Cond: ((disconnect_time >= '2008-09-01 00:00:00'::timestamp without time zone) AND (connect_time <= '2008-09-30 23:59:59'::timestamp without time zone) AND ((elapsed_time > 0) = true)) Total runtime: 43959.783 ms"повезло". но этот индекс не поможет, и запрос будет медленно работать по seqscan в случае, если ограничивающий интервал запросить не последний (сентябрь 2008), а ближе к началу (из имеющихся в таблице данных). попробуйте. WarstoneНо смущает Bitmap Heap Scan для Recheck Cond. Можно этого избежать?не пугайтесь, BitmapIndexScan - это хорошо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.10.2008, 13:32 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
LeXa NalBatно у вас в сентябрьский интервал войдут 1) звонки, начавшиеся раньше сентября и 2) звонки, закончившиеся позже сентября. при этом звонки 1 также войдут в августовский интервал, а звонки 2 - в октябрьский. то есть пограничные звонки вы проанализируете два раза. поэтому правильнее в каждый месяц включть одну границу - например звонки, начавшиеся раньше. соответствующий запрос будет использовать индекс, условие для него: disconnect_time BETWEEN '20080901_000000' AND '20080930_235959'. Согласен, однако это и надо... Звонки идут непереывно и цель не "сделать что-то со всеми звонками", а посчитать максимальное количество одновременно установленных соединений. Вообще там целая хранимая процедура, но она сводится к тому, что собирается таблица времен и она анализируется. В результате находится максимум. С предлагаемым вами подходом в начале каждого месяца количество соединений будет искуственно занижатся. А это не есть правильно. LeXa NalBatне пугайтесь, BitmapIndexScan - это хорошо.Он однако 40 секунд работал. Кстати, а не получится-ли так, что в этой задаче хорошо-бы сделать R индекс, или GiST вроде он щас так называется? По connect/disconnect_time так как задача вроде подходит, но я не нашел разумного объяснения в каком случае применять эти индексы, может кто ссылочкой поделится? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.10.2008, 15:19 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
WarstoneС предлагаемым вами подходом в начале каждого месяца количество соединений будет искуственно занижатся. А это не есть правильно.да, действительно. тогда может у вас получится воспользоваться советом Funny_Falcon "есть ли какое-то максимальное время звонка? Допустим это 12часов, тогда ..." WarstoneОн однако 40 секунд работал.однако он перелопатил и вернул под миллион строк. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.10.2008, 15:44 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
LeXa NalBat WarstoneС предлагаемым вами подходом в начале каждого месяца количество соединений будет искуственно занижатся. А это не есть правильно.да, действительно. тогда может у вас получится воспользоваться советом Funny_Falcon "есть ли какое-то максимальное время звонка? Допустим это 12часов, тогда ..." WarstoneОн однако 40 секунд работал.однако он перелопатил и вернул под миллион строк. Да, но все равно - медленно. Вопрос тогда такой, если поменять запрос на такой: Код: plaintext 1. 2. Кстати, по поводу предложения Funny_Falcon - оно имеет смысл, но вполне возможно, что вместо 1 месяца там будет стоять 1 день. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.10.2008, 16:03 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
WarstoneВопрос тогда такой, если поменять запрос на такой: ... WHERE connect_time BETWEEN ... OR disconnect_time BETWEEN ... Суть не изменится, так как мы выбираем 2 "полосы"теоретически, звонок, начавшийся раньше начала искомого периода (в августе) и закончившийся позже конца (в октябре) не попадает под это условие. если же реально таких звонков нет, то можно. WarstoneКстати, по поводу предложения Funny_Falcon - оно имеет смысл, но вполне возможно, что вместо 1 месяца там будет стоять 1 день.ну и прекрасно, по индексу будут просканированы строки за 36 часов (1день+12часов), и затем отфильтрованы по точному условию. месячный запрос работал 40 секунд, то этот будет порядка 2 секунд. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.10.2008, 16:18 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
LeXa NalBatтеоретически, звонок, начавшийся раньше начала искомого периода (в августе) и закончившийся позже конца (в октябре) не попадает под это условие. если же реально таких звонков нет, то можно.Спасибо, проглядел, действительно может быть. Warstoneну и прекрасно, по индексу будут просканированы строки за 36 часов (1день+12часов), и затем отфильтрованы по точному условию. месячный запрос работал 40 секунд, то этот будет порядка 2 секунд.Щас почитаю внимательней, может пропустил что в его рассуждениях. Однако хочется понять работу RTree может все-таки есть у кого-то что-то? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.10.2008, 16:52 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
Извиняюсь. Я как всегда поспешил и просмотрел, что нужно было выбрать данные за месяц, а не за какой-то момент. Т.е. пик соединений будет считаться внешней прогой ( я так понимаю ) Тогда лучше чем Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. Кстати - решение считать внешней прогой считаю удачным. На чистом SQL я не догадался как достоверно и быстро это решить. Самый дубовый вариант - невероятно тормозит: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.10.2008, 14:44 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
вот еще родилась идея. предполагаю, что для любой строки elapsed_time=connect_time-disconnect_time для удобства обозначений и понимания. длительность звонков во всей таблице имеет распределение Гаусса. выберем несколько границ elapsed_time, в которые попадает примерно одинаковое кол-во звонков, а вне их звонков очень мало. например 1, 3, 10, 30 и 100 минут. создадим sql-функцию elapsed_time_range(elapsed_time) возвращающую 1 для звонков менее одной минуты, 2 - от 1 до 3 минут, и так далее, 5 - от 30 до 100 минут, 6 - более 100 минут. создадим индекс по (elapsed_time_range(elapsed_time),connect_time). переформулируем запрос: where ( elapsed_time_range(elapsed_time)=1 and connect_time between START_TIME-'1 minute' and END_TIME and disconnect_time>=START_TIME ) or ( elapsed_time_range(elapsed_time)=2 and connect_time between START_TIME-'3 minutes' and END_TIME and disconnect_time>=START_TIME ) ... or ( elapsed_time_range(elapsed_time)=5 and connect_time between START_TIME-'5 minutes' and END_TIME and disconnect_time>=START_TIME ) or ( elapsed_time_range(elapsed_time)=6 and connect_time<=END_TIME and disconnect_time>=START_TIME ) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.10.2008, 12:18 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
Пардон за долгое отсутствие... Работа засосала. Funny_FalconТ.е. пик соединений будет считаться внешней прогой ( я так понимаю )Нет, пик считается в хранимой процедуре. Код всей хранимки ниже: Код: 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. Вообще появилась одна идея... Оцените: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. Выбираем минимальный connect_time у активных звонков на начале периода, если такового нет, то ставим начало периода Выбираем максимальный connect_time у активных звонков в конце периода, если нет, берем конец периода. Выбираем звонки у котрых connect_time в промежутке и elapsed>0. В купе с: Код: plaintext 1. 2. 3. 4. 5. 6. 7. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.10.2008, 16:32 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
Опять-таки не нравится фраза Bitmap Heap Scan. Хоть он тут и идет по 80К записей, а не по 800К как в предидущем случае, но... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.10.2008, 16:38 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
Да кстати, mera_traffic_connect_time2 - не нужен. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.10.2008, 16:40 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
И кто-нить объясните почему Код: plaintext 1. 2. Код: plaintext 1. 2. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.10.2008, 16:45 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
WarstoneCREATE TEMP TABLE temp_calls AS ( SELECT connect_time, disconnect_time FROM mera_traffic WHERE disconnect_time>=t_from AND connect_time<=t_to AND elapsed_time>0 AND hub_id=i_hub_id ); SELECT times, MAX(entries) INTO peak_time, peak FROM ( SELECT q.times, COUNT(*) AS entries FROM ( SELECT DISTINCT connect_time as times FROM temp_calls ) AS q LEFT JOIN temp_calls tc ON tc.connect_time<=q.times AND tc.disconnect_time>=q.times GROUP BY q.times ) AS w GROUP BY times ORDER BY 2 DESC; В принципе можно и одним SQL если использовать конструкцию WITH q AS() SELECT (Или как она точно звучит)для этой задачи пробежаться в plpgsql в цикле по строкам изменяя счетчик (кол-во соединений) наверное будет быстрее, чем делать self-join select connect_time, count(*) as connect_num from temp_calls group by 1 -- IndexScan по connect_time, GroupAggregate full outer join -- MergeJoin select disconnect_time, count(*) as disconnect_num from temp_calls group by 1 -- IndexScan по disconnect_time, GroupAggregate on ( connect_time = disconnect_time ) далее в plgpsql: cur:=0 max:=0 далее для каждой строки: cur:=cur+connect_num-disconnect_num max:=cur if max<cur причем наверное будет быстрее сделать аналогично, но без временной таблицы PS: с этим запросом засада: для того чтобы гарантированно получить результат отсортированный по coalesce(connect_time,disconnect_time) нужно явно указать условие order by. но тогда постгрес будет делать лишнюю сортировку, хотя на самом деле она не нужна. так что, или перестраховываться и получать запрос медленнее, или "рисковать" и получать более быстрый запрос. я писал об этом в рассылку: урл WarstoneEXPLAIN ANALYZE SELECT connect_time, disconnect_time FROM mera_traffic LEFT JOIN ( SELECT CASE WHEN MIN(connect_time) IS NULL THEN '20080901_000000' ELSE MIN(connect_time) END AS begin_time FROM mera_traffic WHERE '20080901_000000' BETWEEN connect_time AND disconnect_time AND elapsed_time>0 ) AS q ON 1=1 LEFT JOIN ( SELECT CASE WHEN MAX(connect_time) IS NULL THEN '20080929_235959' ELSE MAX(connect_time) END AS end_time FROM mera_traffic WHERE '20080929_235959' BETWEEN connect_time AND disconnect_time AND elapsed_time>0 ) AS w ON 1=1 WHERE connect_time BETWEEN q.begin_time AND w.end_time AND elapsed_time>0кажется, в этом запросе ошибка. проверку на null надо ставить не в select-е подзапроса, а в where основного запроса, потому что select подзапроса может не вернуть ни одной строки. select 1 = ( select 1 ); -- true select 1 = ( select 1 limit 0 ); -- null PS: ON 1=1 - это cross join. или имхо понятнее записать select mera_traffic, ( select min ... ) as begin_time, ( select min ... ) as end_time from mera_traffic where ... Warstone Смысл такой: Выбираем минимальный connect_time у активных звонков на начале периода, если такового нет, то ставим начало периода Выбираем максимальный connect_time у активных звонков в конце периода, если нет, берем конец периода. Выбираем звонки у котрых connect_time в промежутке и elapsed>0.не понятно, в чем может быть выигрыш, "из пустого в порожнее". WarstoneОн дает вот что: ... Что в принципе гораздо быстрее 40 секунд.не понятно. 40 секунд было на 800 тысяч строк, а этот запрос вернул только 120 тысяч, почему? покажите пожалуйста: select count(*) from mera_traffic; select count(*) from mera_traffic where connect_time < '20080901_000000'; select count(*) from mera_traffic where connect_time between '20080901_000000' and '20080929_235959'; select count(*) from mera_traffic where connect_time > '20080929_235959'; PS: тестировать на скорость выполнения надо реальные интересующие запросы на реальных тестовых данных ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.10.2008, 12:13 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
>кажется, в этом запросе ошибка. проверку на null надо ставить не в select-е подзапроса, а в where основного запроса, потому что select подзапроса может не вернуть ни одной строки. Именно поэтому там CASE и стоит. Он всегда возвращает 1 строку в которой может быть NULL. Этот CASE гарантирует что NULL'а не будет. >не понятно, в чем может быть выигрыш, "из пустого в порожнее". Конечный SELECT идет по 1-му параметру. Хотя вобщем-то вы правы, об этом ниже... >PS: ON 1=1 - это cross join. или имхо понятнее записать select mera_traffic, ( select min ... ) as begin_time, ( select min ... ) as end_time from mera_traffic where ... Более того... План выполнения запроса меняется на более оптимальный! Спасибо за ответ. По поводу количества - не видел... Я просто по месяцу за каждый день прогнал сравнения и получил одно и то-же... Правда тут засада: Это далеко не панацея. Так как пример был вырожденый, первая запись датирована 1-м сентября. Поэтому не вариант. Походу универсальный запрос тут не сделаешь. Тогда немного поменяю задачу... Известно что скорее всего будут выбирать данные из конца хранимого промежутка. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.10.2008, 13:31 |
|
||
|
Помогите создать индекс.
|
|||
|---|---|---|---|
|
#18+
WarstoneИменно поэтому там CASE и стоит. Он всегда возвращает 1 строку в которой может быть NULL. Этот CASE гарантирует что NULL'а не будет.да, вы правы. я ошибся, полагая, что выборка глобального (без group by) минимума по пустому набору строк не вернет ни одной строки, а на самом деле возвращает null Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. WarstoneПоходу универсальный запрос тут не сделаешь.если примерно можно предположить характеристики распределения elapsed_time, то кажется предложенный мной ранее вариант подойдет. но только для решения задачи, сформулированной вами в первом посте. потому что строки получатся не упорядочены нужным образом для их последующего потокового анализа с помощью plgpsql и счетчика. WarstoneТогда немного поменяю задачу... Известно что скорее всего будут выбирать данные из конца хранимого промежутка.это проще. выберется мало ненужных строк кроме искомых при использовании условия "больше либо равно". такое условие в запросе на поле disconnect_time, значит надо чтобы запрос выполнялся по индексу (disconnect_time). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.10.2008, 17:02 |
|
||
|
|

start [/forum/topic.php?fid=53&msg=35586046&tid=2003948]: |
0ms |
get settings: |
8ms |
get forum list: |
19ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
59ms |
get topic data: |
13ms |
get forum data: |
3ms |
get page messages: |
73ms |
get tp. blocked users: |
2ms |
| others: | 245ms |
| total: | 430ms |

| 0 / 0 |
