Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Помогите создать индекс. / 20 сообщений из 20, страница 1 из 1
08.10.2008, 18:34
    #35584061
Warstone
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
Есть такой запрос:
Код: plaintext
1.
2.
SELECT connect_time, disconnect_time
		FROM mera_traffic
		WHERE disconnect_time>='20080901_000000' AND connect_time<='20080930_235959' AND elapsed_time> 0  AND hub_id= 1 
Даты меняются.
Нужен он для того, чтоб потом можно было посчитать пик одновременных звонков.
Вопрос в том как создать под это дело индекс, так чтоб ускорить этот запрос. Пока пытался сделать вот что:
Код: plaintext
1.
2.
3.
CREATE INDEX mera_traffic_connect_time
  ON mera_traffic
  USING btree
  (hub_id, connect_time, disconnect_time, elapsed_time);
Но он упорно не хочет идти но нему. Похоже что надо делать RTree для connect/disconnect time, но в hub_id отсилы 3-4 значения, а elapsed_time просто должно быть больше 0. То есть прямой RTree не подходит... Что делать?
...
Рейтинг: 0 / 0
09.10.2008, 10:07
    #35584775
LeXa NalBat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
можно ли вместо указанного вами использовать запрос, который не выбирает соединения, приходящиеся на границы интервала?

connect_time>='20080901_000000' AND disconnect_time<='20080930_235959'

тогда, учитывая что connect_time<=disconnect_time, можно будет добавить в запрос дополнительные условия для ускорения:

disconnect_time>='20080901_000000' AND connect_time<='20080930_235959'

для такого запроса может использоваться индекс, показывайте EXPLAIN ANALYZE.
...
Рейтинг: 0 / 0
09.10.2008, 10:08
    #35584777
Funny_Falcon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
Во первых, снеси этот индекс и попробуй по очереди:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
CREATE INDEX mera_traffic_connect_time
  ON mera_traffic
  USING btree
  (disconnect_time, connect_time);
-- Или
CREATE INDEX mera_traffic_connect_time
  ON mera_traffic
  USING btree
  (connect_time, disconnect_time);
Т.е. hub_id - сносится обязательно, elapsed_time тоже не нужен.
Во-вторых: есть ли какое-то максимальное время звонка? Допустим это 12часов, и есть индекс по (connect_time, disconnect_time), тогда запрос приобретает вид:
Код: plaintext
1.
2.
3.
4.
SELECT connect_time, disconnect_time
		FROM mera_traffic
		WHERE disconnect_time>='20080901_000000' AND connect_time BETWEEN '20080930_115959' AND '20080930_235959'  
                AND elapsed_time> 0  AND hub_id= 1 
...
Рейтинг: 0 / 0
09.10.2008, 12:05
    #35585166
Warstone
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
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.
"Seq Scan on mera_traffic  (cost=0.00..543120.68 rows=798672 width=16)"
"  Filter: ((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) AND (hub_id = 1))"
Analyze - Чуть позже. Funny_Falcon Во-вторых: есть ли какое-то максимальное время звонка? Допустим это 12часов, и есть индекс по (connect_time, disconnect_time), тогда запрос приобретает вид:А разница между >= и BETWEEN?
...
Рейтинг: 0 / 0
09.10.2008, 12:34
    #35585278
Warstone
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
Сейчас попробовал сделать вот такой индекс:
Код: plaintext
1.
2.
3.
CREATE INDEX mera_traffic_connect_time2
  ON mera_traffic
  USING btree
  (disconnect_time, elapsed_time, (connect_time> 0 ));
Тогда запрос
Код: plaintext
1.
2.
EXPLAIN ANALYZE SELECT connect_time, disconnect_time
		FROM mera_traffic
		WHERE disconnect_time>='20080901_000000' AND connect_time<='20080930_235959' AND elapsed_time> 0 
Пошел под другому плану
Код: plaintext
1.
2.
3.
4.
5.
Bitmap Heap Scan on mera_traffic  (cost= 62230 . 96 .. 409273 . 29  rows= 801075  width= 16 ) (actual time= 3545 . 171 .. 42675 . 544  rows= 868195  loops= 1 )
  Recheck 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))
  Filter: (elapsed_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
Но смущает Bitmap Heap Scan для Recheck Cond. Можно этого избежать?
И кстати, может имеет смысл сделать хранимую процедуру и там с помощью курсоров чего-нибудь добиться?
...
Рейтинг: 0 / 0
09.10.2008, 13:32
    #35585506
LeXa NalBat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
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 - это хорошо.
...
Рейтинг: 0 / 0
09.10.2008, 15:19
    #35585900
Warstone
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
LeXa NalBatно у вас в сентябрьский интервал войдут 1) звонки, начавшиеся раньше сентября и 2) звонки, закончившиеся позже сентября. при этом звонки 1 также войдут в августовский интервал, а звонки 2 - в октябрьский. то есть пограничные звонки вы проанализируете два раза. поэтому правильнее в каждый месяц включть одну границу - например звонки, начавшиеся раньше. соответствующий запрос будет использовать индекс, условие для него: disconnect_time BETWEEN '20080901_000000' AND '20080930_235959'.


Согласен, однако это и надо... Звонки идут непереывно и цель не "сделать что-то со всеми звонками", а посчитать максимальное количество одновременно установленных соединений. Вообще там целая хранимая процедура, но она сводится к тому, что собирается таблица времен и она анализируется. В результате находится максимум. С предлагаемым вами подходом в начале каждого месяца количество соединений будет искуственно занижатся. А это не есть правильно.
LeXa NalBatне пугайтесь, BitmapIndexScan - это хорошо.Он однако 40 секунд работал. Кстати, а не получится-ли так, что в этой задаче хорошо-бы сделать R индекс, или GiST вроде он щас так называется? По connect/disconnect_time так как задача вроде подходит, но я не нашел разумного объяснения в каком случае применять эти индексы, может кто ссылочкой поделится?
...
Рейтинг: 0 / 0
09.10.2008, 15:44
    #35585991
LeXa NalBat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
WarstoneС предлагаемым вами подходом в начале каждого месяца количество соединений будет искуственно занижатся. А это не есть правильно.да, действительно. тогда может у вас получится воспользоваться советом Funny_Falcon "есть ли какое-то максимальное время звонка? Допустим это 12часов, тогда ..."

WarstoneОн однако 40 секунд работал.однако он перелопатил и вернул под миллион строк.
...
Рейтинг: 0 / 0
09.10.2008, 16:03
    #35586046
Warstone
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
LeXa NalBat WarstoneС предлагаемым вами подходом в начале каждого месяца количество соединений будет искуственно занижатся. А это не есть правильно.да, действительно. тогда может у вас получится воспользоваться советом Funny_Falcon "есть ли какое-то максимальное время звонка? Допустим это 12часов, тогда ..."

WarstoneОн однако 40 секунд работал.однако он перелопатил и вернул под миллион строк.
Да, но все равно - медленно. Вопрос тогда такой, если поменять запрос на такой:
Код: plaintext
1.
2.
SELECT connect_time, disconnect_time
		FROM mera_traffic
		WHERE ((connect_time BETWEEN '20080901_000000' AND '20080930_235959') OR (disconnect_time BETWEEN '20080901_000000' AND '20080930_235959')) AND elapsed_time> 0 
Суть не изменится, так как мы выбираем 2 "полосы" но может тут можно применть RTree? Или я лезу в дебри?

Кстати, по поводу предложения Funny_Falcon - оно имеет смысл, но вполне возможно, что вместо 1 месяца там будет стоять 1 день.
...
Рейтинг: 0 / 0
09.10.2008, 16:18
    #35586106
LeXa NalBat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
WarstoneВопрос тогда такой, если поменять запрос на такой: ... WHERE connect_time BETWEEN ... OR disconnect_time BETWEEN ...
Суть не изменится, так как мы выбираем 2 "полосы"теоретически, звонок, начавшийся раньше начала искомого периода (в августе) и закончившийся позже конца (в октябре) не попадает под это условие. если же реально таких звонков нет, то можно.

WarstoneКстати, по поводу предложения Funny_Falcon - оно имеет смысл, но вполне возможно, что вместо 1 месяца там будет стоять 1 день.ну и прекрасно, по индексу будут просканированы строки за 36 часов (1день+12часов), и затем отфильтрованы по точному условию. месячный запрос работал 40 секунд, то этот будет порядка 2 секунд.
...
Рейтинг: 0 / 0
09.10.2008, 16:52
    #35586229
Warstone
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
LeXa NalBatтеоретически, звонок, начавшийся раньше начала искомого периода (в августе) и закончившийся позже конца (в октябре) не попадает под это условие. если же реально таких звонков нет, то можно.Спасибо, проглядел, действительно может быть. Warstoneну и прекрасно, по индексу будут просканированы строки за 36 часов (1день+12часов), и затем отфильтрованы по точному условию. месячный запрос работал 40 секунд, то этот будет порядка 2 секунд.Щас почитаю внимательней, может пропустил что в его рассуждениях.
Однако хочется понять работу RTree может все-таки есть у кого-то что-то?
...
Рейтинг: 0 / 0
11.10.2008, 14:44
    #35589449
Funny_Falcon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
Извиняюсь. Я как всегда поспешил и просмотрел, что нужно было выбрать данные за месяц, а не за какой-то момент.
Т.е. пик соединений будет считаться внешней прогой ( я так понимаю )

Тогда лучше чем
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
EXPLAIN ANALYZE SELECT connect_time, disconnect_time
		FROM mera_traffic
		WHERE disconnect_time>='20080901_000000' AND connect_time<='20080930_235959' AND elapsed_time> 0 

Bitmap Heap Scan on mera_traffic  (cost= 62230 . 96 .. 409273 . 29  rows= 801075  width= 16 ) (actual time= 3545 . 171 .. 42675 . 544  rows= 868195  loops= 1 )
  Recheck 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))
  Filter: (elapsed_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
ты не получишь - и это нормально. Выборка "всего за месяц" и не может быть быстрой.

Кстати - решение считать внешней прогой считаю удачным.
На чистом SQL я не догадался как достоверно и быстро это решить.
Самый дубовый вариант - невероятно тормозит:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
SELECT moment, count(*)
FROM mera_traffic m 
JOIN ( select ('2008-09-01 00:00:00'+'1 minute'::interval * i) as moment
         from generate_series(  0 , (extract( epoch from '2008-10-01') - extract( epoch from '2008-09-01' ) )/ 60 ::integer) as i
       ) t
   ON m.connect_time BETWEEN moment-'12 hours'::interval AND moment
WHERE elapsed_time> 0 
GROUP BY moment
...
Рейтинг: 0 / 0
13.10.2008, 12:18
    #35590945
LeXa NalBat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
вот еще родилась идея. предполагаю, что для любой строки 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 )
...
Рейтинг: 0 / 0
20.10.2008, 16:32
    #35604774
Warstone
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
Пардон за долгое отсутствие... Работа засосала.
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.
CREATE OR REPLACE FUNCTION mera_calc_peak(IN i_hub_id bigint, IN t_from timestamp without time zone, IN t_to timestamp without time zone, OUT peak_time timestamp without time zone, OUT peak bigint)
  RETURNS record AS
$BODY$
BEGIN
	BEGIN DROP TABLE temp_calls; EXCEPTION WHEN others THEN END;
	CREATE 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;
	DROP TABLE temp_calls;
	RETURN;
END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE
  COST  100 ;
В принципе можно и одним SQL если использовать конструкцию WITH q AS() SELECT (Или как она точно звучит)

Вообще появилась одна идея... Оцените:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
EXPLAIN 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 
Смысл такой:
Выбираем минимальный connect_time у активных звонков на начале периода, если такового нет, то ставим начало периода
Выбираем максимальный connect_time у активных звонков в конце периода, если нет, берем конец периода.
Выбираем звонки у котрых connect_time в промежутке и elapsed>0.
В купе с:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
CREATE INDEX mera_traffic_connect_time
  ON mera_traffic
  USING btree
  (connect_time, (elapsed_time >  0 ));
CREATE INDEX mera_traffic_connect_time2
  ON mera_traffic
  USING btree
  (disconnect_time, connect_time, (elapsed_time >  0 ));
Он дает вот что:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
"Nested Loop  (cost=4076.72..23345.90 rows=24386 width=16) (actual time=87.862..1352.042 rows=128369 loops=1)"
"  Join Filter: (public.mera_traffic.connect_time >= (CASE WHEN ($0 IS NULL) THEN '2008-09-01 00:00:00'::timestamp without time zone ELSE $0 END))"
"  ->  Result  (cost=2.73..2.74 rows=1 width=0) (actual time=0.476..0.478 rows=1 loops=1)"
"        InitPlan"
"          ->  Limit  (cost=0.00..2.73 rows=1 width=8) (actual time=0.468..0.468 rows=0 loops=1)"
"                ->  Index Scan using mera_traffic_connect_time on mera_traffic  (cost=0.00..59.96 rows=22 width=8) (actual time=0.464..0.464 rows=0 loops=1)"
"                      Index Cond: (('2008-09-01 00:00:00'::timestamp without time zone >= connect_time) AND ((elapsed_time > 0) = true))"
"                      Filter: ((connect_time IS NOT NULL) AND ('2008-09-01 00:00:00'::timestamp without time zone <= disconnect_time) AND (elapsed_time > 0))"
"  ->  Nested Loop  (cost=4073.99..22428.69 rows=73157 width=16) (actual time=87.374..942.433 rows=128369 loops=1)"
"        ->  Result  (cost=1.23..1.24 rows=1 width=0) (actual time=0.094..0.096 rows=1 loops=1)"
"              InitPlan"
"                ->  Limit  (cost=0.00..1.23 rows=1 width=8) (actual time=0.083..0.085 rows=1 loops=1)"
"                      ->  Index Scan Backward using mera_traffic_connect_time on mera_traffic  (cost=0.00..64325.86 rows=52247 width=8) (actual time=0.080..0.080 rows=1 loops=1)"
"                            Index Cond: (('2008-09-29 23:59:59'::timestamp without time zone >= connect_time) AND ((elapsed_time > 0) = true))"
"                            Filter: ((connect_time IS NOT NULL) AND ('2008-09-29 23:59:59'::timestamp without time zone <= disconnect_time) AND (elapsed_time > 0))"
"        ->  Bitmap Heap Scan on mera_traffic  (cost=4072.76..21336.10 rows=87307 width=16) (actual time=87.267..539.106 rows=128369 loops=1)"
"              Recheck Cond: (public.mera_traffic.connect_time <= (CASE WHEN ($1 IS NULL) THEN '2008-09-29 23:59:59'::timestamp without time zone ELSE $1 END))"
"              Filter: (public.mera_traffic.elapsed_time > 0)"
"              ->  Bitmap Index Scan on mera_traffic_connect_time  (cost=0.00..4054.47 rows=87307 width=0) (actual time=81.984..81.984 rows=128369 loops=1)"
"                    Index Cond: ((public.mera_traffic.connect_time <= (CASE WHEN ($1 IS NULL) THEN '2008-09-29 23:59:59'::timestamp without time zone ELSE $1 END)) AND ((public.mera_traffic.elapsed_time > 0) = true))"
"Total runtime: 1540.309 ms"
Что в принципе гораздо быстрее 40 секунд.
...
Рейтинг: 0 / 0
20.10.2008, 16:38
    #35604785
Warstone
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
Опять-таки не нравится фраза Bitmap Heap Scan. Хоть он тут и идет по 80К записей, а не по 800К как в предидущем случае, но...
...
Рейтинг: 0 / 0
20.10.2008, 16:40
    #35604794
Warstone
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
Да кстати, mera_traffic_connect_time2 - не нужен.
...
Рейтинг: 0 / 0
20.10.2008, 16:45
    #35604813
Warstone
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
И кто-нить объясните почему
Код: plaintext
1.
2.
SELECT connect_time, disconnect_time
	FROM mera_traffic
WHERE connect_time BETWEEN '20080901_000000' AND '20080929_235959' AND elapsed_time> 0 
(Просто тест на скорость без нахождения точных границ) Дает вто что:
Код: plaintext
1.
2.
"Seq Scan on mera_traffic  (cost=0.00..25354.94 rows=133803 width=16) (actual time=0.024..5592.228 rows=128369 loops=1)"
"  Filter: ((connect_time >= '2008-09-01 00:00:00'::timestamp without time zone) AND (connect_time <= '2008-09-29 23:59:59'::timestamp without time zone) AND (elapsed_time > 0))"
"Total runtime: 5786.737 ms"
и идет медленнее чем с границами?
...
Рейтинг: 0 / 0
21.10.2008, 12:13
    #35606251
LeXa NalBat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
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: тестировать на скорость выполнения надо реальные интересующие запросы на реальных тестовых данных
...
Рейтинг: 0 / 0
22.10.2008, 13:31
    #35609102
Warstone
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
>кажется, в этом запросе ошибка. проверку на 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-м сентября. Поэтому не вариант.

Походу универсальный запрос тут не сделаешь. Тогда немного поменяю задачу... Известно что скорее всего будут выбирать данные из конца хранимого промежутка.
...
Рейтинг: 0 / 0
22.10.2008, 17:02
    #35609871
LeXa NalBat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите создать индекс.
WarstoneИменно поэтому там CASE и стоит. Он всегда возвращает 1 строку в которой может быть NULL. Этот CASE гарантирует что NULL'а не будет.да, вы правы. я ошибся, полагая, что выборка глобального (без group by) минимума по пустому набору строк не вернет ни одной строки, а на самом деле возвращает null

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
nalbat=> select * from ( select  1  as x where false ) as x;
 x
---
( 0  rows)

nalbat=> select min(x) from ( select  1  as x where false ) as x;
 min
-----

( 1  row)

nalbat=> select 'dummy' as dummy, min(x) from ( select  1  as x where false ) as x group by dummy;
 dummy | min
-------+-----
( 0  rows)

WarstoneПоходу универсальный запрос тут не сделаешь.если примерно можно предположить характеристики распределения elapsed_time, то кажется предложенный мной ранее вариант подойдет. но только для решения задачи, сформулированной вами в первом посте. потому что строки получатся не упорядочены нужным образом для их последующего потокового анализа с помощью plgpsql и счетчика.

WarstoneТогда немного поменяю задачу... Известно что скорее всего будут выбирать данные из конца хранимого промежутка.это проще. выберется мало ненужных строк кроме искомых при использовании условия "больше либо равно". такое условие в запросе на поле disconnect_time, значит надо чтобы запрос выполнялся по индексу (disconnect_time).
...
Рейтинг: 0 / 0
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Помогите создать индекс. / 20 сообщений из 20, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]