2012-05-16 1 views
1

Я кластерных данных по нескольким таблицам, как правило, они выглядят следующим образом:UNION ALL занимает слишком много времени

CREATE TABLE 2012_03_09 (
    guid_key integer, 
    property_key integer, 
    instance_id_key integer, 
    time_stamp timestamp without time zone, 
    "value" double precision 
) 

с этими индексами:

CREATE INDEX 2012_03_09_a 
    ON 2012_03_09 
    USING btree 
    (guid_key, property_key, time_stamp); 

CREATE INDEX 2012_03_09_b 
    ON 2012_03_09 
    USING btree 
    (time_stamp, property_key); 

Когда я анализирую свои запросы, общее количество времени для добавления операций беспокоит меня. Можете ли вы объяснить мне, почему запрос работает слишком долго? Есть ли способ оптимизировать такой запрос?

Sort (cost=262.50..262.61 rows=47 width=20) (actual time=1918.237..1918.246 rows=100 loops=1)  
    Output: 2012_04_26.time_stamp, 2012_04_26.value, 2012_04_26.instance_id_key  
    Sort Key: 2012_04_26.instance_id_key, 2012_04_26.time_stamp  
    Sort Method: quicksort Memory: 32kB  
    -> Append (cost=0.00..261.19 rows=47 width=20) (actual time=69.817..1917.848 rows=100 loops=1)  
     -> Index Scan using 2012_04_26_a on 2012_04_26 (cost=0.00..8.28 rows=1 width=20) (actual time=14.909..14.909 rows=0 loops=1)  
       Output: 2012_04_26.time_stamp, 2012_04_26.value, 2012_04_26.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
     -> Index Scan using 2012_04_27_a on 2012_04_27 (cost=0.00..8.28 rows=1 width=20) (actual time=1.535..1.535 rows=0 loops=1)  
       Output: 2012_04_27.time_stamp, 2012_04_27.value, 2012_04_27.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
     -> Index Scan using 2012_05_02_a on 2012_05_02 (cost=0.00..12.50 rows=2 width=20) (actual time=53.370..121.894 rows=6 loops=1)  
       Output: 2012_05_02.time_stamp, 2012_05_02.value, 2012_05_02.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
     -> Index Scan using 2012_05_03_a on 2012_05_03 (cost=0.00..24.74 rows=5 width=20) (actual time=59.136..170.215 rows=11 loops=1)  
       Output: 2012_05_03.time_stamp, 2012_05_03.value, 2012_05_03.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
     -> Index Scan using 2012_05_04_a on 2012_05_04 (cost=0.00..12.47 rows=2 width=20) (actual time=67.458..125.172 rows=5 loops=1)  
       Output: 2012_05_04.time_stamp, 2012_05_04.value, 2012_05_04.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
     -> Index Scan using 2012_05_05_a on 2012_05_05 (cost=0.00..8.28 rows=1 width=20) (actual time=14.112..14.112 rows=0 loops=1)  
       Output: 2012_05_05.time_stamp, 2012_05_05.value, 2012_05_05.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
     -> Index Scan using 2012_05_07_a on 2012_05_07 (cost=0.00..12.46 rows=2 width=20) (actual time=60.549..99.999 rows=4 loops=1)  
       Output: 2012_05_07.time_stamp, 2012_05_07.value, 2012_05_07.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
     -> Index Scan using 2012_05_08_a on 2012_05_08 (cost=0.00..24.71 rows=5 width=20) (actual time=63.367..197.296 rows=12 loops=1)  
       Output: 2012_05_08.time_stamp, 2012_05_08.value, 2012_05_08.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
     -> Index Scan using 2012_05_09_a on 2012_05_09 (cost=0.00..28.87 rows=6 width=20) (actual time=59.596..224.685 rows=15 loops=1)  
       Output: 2012_05_09.time_stamp, 2012_05_09.value, 2012_05_09.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
     -> Index Scan using 2012_05_10_a on 2012_05_10 (cost=0.00..28.85 rows=6 width=20) (actual time=56.995..196.590 rows=13 loops=1)  
       Output: 2012_05_10.time_stamp, 2012_05_10.value, 2012_05_10.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
     -> Index Scan using 2012_05_11_a on 2012_05_11 (cost=0.00..20.59 rows=4 width=20) (actual time=62.761..134.313 rows=8 loops=1)  
       Output: 2012_05_11.time_stamp, 2012_05_11.value, 2012_05_11.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
     -> Index Scan using 2012_05_12_a on 2012_05_12 (cost=0.00..8.28 rows=1 width=20) (actual time=12.018..12.018 rows=0 loops=1)  
       Output: 2012_05_12.time_stamp, 2012_05_12.value, 2012_05_12.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
     -> Index Scan using 2012_05_13_a on 2012_05_13 (cost=0.00..8.28 rows=1 width=20) (actual time=12.286..12.286 rows=0 loops=1)  
       Output: 2012_05_13.time_stamp, 2012_05_13.value, 2012_05_13.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
     -> Index Scan using 2012_05_14_a on 2012_05_14 (cost=0.00..16.58 rows=3 width=20) (actual time=92.161..156.802 rows=6 loops=1)  
       Output: 2012_05_14.time_stamp, 2012_05_14.value, 2012_05_14.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
     -> Index Scan using 2012_05_15_a on 2012_05_15 (cost=0.00..25.03 rows=5 width=20) (actual time=73.636..263.537 rows=14 loops=1)  
       Output: 2012_05_15.time_stamp, 2012_05_15.value, 2012_05_15.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
     -> Index Scan using 2012_05_16_a on 2012_05_16 (cost=0.00..12.56 rows=2 width=20) (actual time=100.893..172.404 rows=6 loops=1)  
       Output: 2012_05_16.time_stamp, 2012_05_16.value, 2012_05_16.instance_id_key  
       Index Cond: ((guid_key = 2105) AND (property_key = 67) AND (time_stamp >= '2012-04-16 00:00:00'::timestamp without time zone) AND (time_stamp <= '2012-05-16 06:25:50.172'::timestamp without time zone))  
Total runtime: 1918.745 ms 

UPDATE:

Проводка также SQL-запрос:

select time_stamp, value, instance_id_key as segment from perf_hourly_2012_04_26 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
UNION ALL 
select time_stamp, value, instance_id_key as segment from 2012_04_27 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
UNION ALL 
select time_stamp, value, instance_id_key as segment from 2012_05_02 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
UNION ALL 
select time_stamp, value, instance_id_key as segment from 2012_05_03 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
UNION ALL 
select time_stamp, value, instance_id_key as segment from 2012_05_04 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
UNION ALL 
select time_stamp, value, instance_id_key as segment from 2012_05_05 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
UNION ALL 
select time_stamp, value, instance_id_key as segment from 2012_05_07 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
UNION ALL 
select time_stamp, value, instance_id_key as segment from 2012_05_08 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
UNION ALL 
select time_stamp, value, instance_id_key as segment from 2012_05_09 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
UNION ALL 
select time_stamp, value, instance_id_key as segment from 2012_05_10 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
UNION ALL 
select time_stamp, value, instance_id_key as segment from 2012_05_11 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
UNION ALL 
select time_stamp, value, instance_id_key as segment from 2012_05_12 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
UNION ALL 
select time_stamp, value, instance_id_key as segment from 2012_05_13 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
UNION ALL 
select time_stamp, value, instance_id_key as segment from 2012_05_14 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
UNION ALL 
select time_stamp, value, instance_id_key as segment from 2012_05_15 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
UNION ALL 
select time_stamp, value, instance_id_key as segment from 2012_05_16 where guid_key = 2105 and property_key=67 and time_stamp between '2012-04-16 00:00:00.0'::timestamp without time zone and '2012-05-16 06:25:50.172'::timestamp without time zone 
ORDER BY 3 ASC, 1 ASC 
+2

почтовый запрос, который вы используете –

+0

Я обновил исходное сообщение, спасибо за внимание –

+1

Сколько записей возвращает запрос? – Quassnoi

ответ

2

Помимо добавления, все строки, как представляется, получают сканирование индексов первого типа. Я должен был подумать, если это лучший показатель для этого. Поскольку вы, кажется, выбираете значительные диапазоны времени, единственными другими вариантами являются guid_key и property_key. Что более избирательно? Чем более избирательный столбец должен быть первым (то есть, если вас не беспокоит сортировка, что я не думаю, что вы должны быть за 100 строк). Во-вторых, вы добавили эти индексы для целей этого запроса или других запросов? Это может иметь смысл бросить их, если они не полезны нигде. Индексы могут фактически замедлять производительность, особенно если записи таблицы уже хранятся в памяти большую часть времени, так как они могут потребовать, чтобы база данных выгружала записи из памяти для загрузки индекса (а затем загружала записи таблицы после завершения работы с индексированием).

Единственное реальное предложение здесь я могу дать играть с ним.

Edit:

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

2

Похоже, что вы должны проверить Postgresql Partitioning. Ваш запрос будет проще, и он может работать лучше (не на 100% уверен, но я думаю, что стоит попробовать)

1

UNION - это не ваша проблема с временем, сообщенное истекшее время в основном представляет собой сумму времени сканирования индекса каждого раздела. Ваши индексы _a выглядят соответственно выборочными для вашего предиката запроса. Критик реального времени, который я вижу в анализе объяснения, заключается в том, что требуется много времени, чтобы получить всего несколько строк с индексированием по каждому разделу. например: 125 мс для 5 строк в 2012_05_04. Сканирование индекса должно вызывать, возможно, 0-5 запросов в зависимости от состояния кэша и размера таблицы, и если данные не кластеризованы, тогда будет один поиск в строке данных. Медленный одиночный шпиндельный диск должен иметь возможность выполнять поиск и блочную выборку в ~ 10 мс, поэтому наихудший случай для этого сканирования с дерьмовой системой хранения составляет около 100 мс, но с более распространенными дисками 7200 или 10 000 об/мин и несколькими шпинделями наихудший если предположить, что кеш-хиты не должны быть менее 50 мс. При приличном хранении кэша я ожидал бы не более нескольких десятков миллисекунд для сканирования индекса каждого раздела.

Выполняется ли этот запрос быстрее при повторной попытке сразу после первого? Если это так, это указывает на медленное хранение с холодным кешем в качестве проблемы. В каком хранилище работает база данных? Если мы говорим о медленном ноутбуке или высокоскоростном сетевом креплении, это объясняет бедный IO perf. На сканирование индекса также может влиять экстремальный раздувание индекса. Если у вас есть десятки или сотни мертвых индексных записей из-за обновления/удаления оттока данных с неправильным режимом вакуума, то это может быть преступником.Регулярно ли эти таблицы регулярно анализируются и анализируются?

Как предложил Адриан Серафин, вы должны изучить особенности разбивки таблиц Pg.