Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Оптимизация Postgres для огромных таблиц / 16 сообщений из 16, страница 1 из 1
27.04.2006, 09:17
    #33693325
postt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
Что нужно сделать,чтобы оптимизировать работы Postgres на огромных таблицах. Например долго выполняется запрос вида ( причем операции с индексом тоже работают долго)
EXPLAIN SELECT sum(bytes)::double precision,to_char(date_trunc('day',second),'DD')::text AS ds,name,clients2.id FROM iptables,net_addr,clients2 WHERE net_addr.ip::inet=iptables.dest::inet and clients2.id::int=net_addr.id::int and second BETWEEN '2006-04-01 00:00:00'::date and '2006-04-10 00:00:00'::date GROUP BY clients2.id::int,name::text,ds ORDER BY name,ds;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Sort (cost=132056.49..132544.72 rows=195292 width=36)
Sort Key: clients2.name, to_char(date_trunc('day'::text, iptables."second"), 'DD'::text)
-> GroupAggregate (cost=103396.11..109739.93 rows=195292 width=36)
-> Sort (cost=103396.11..104371.93 rows=390331 width=36)
Sort Key: clients2.id, clients2.name, to_char(date_trunc('day'::text, iptables."second"), 'DD'::text)
-> Hash Join (cost=56.63..42555.41 rows=390331 width=36)
Hash Cond: ("outer".dest = "inner".ip)
-> Index Scan using idx_second on iptables (cost=0.00..34692.16 rows=390331 width=27)
Index Cond: (("second" >= '2006-04-01 00:00:00'::timestamp without time zone) AND ("second" <= '2006-04-10 00:00:00'::timestamp without time zone))
-> Hash (cost=54.26..54.26 rows=947 width=31)
-> Hash Join (cost=20.59..54.26 rows=947 width=31)
Hash Cond: ("outer".id = "inner".id)
-> Seq Scan on net_addr (cost=0.00..19.47 rows=947 width=15)
-> Hash (cost=18.47..18.47 rows=847 width=20)
-> Seq Scan on clients2 (cost=0.00..18.47 rows=847 width=20)
(15 rows)
EXPLAIN SELECT sum(bytes)::double precision,to_char(date_trunc('day',second),'DD')::text AS ds,name,clients2.id FROM iptables,net_addr,clients2 WHERE net_addr.ip::inet=iptables.dest::inet and clients2.id::int=net_addr.id::int and second BETWEEN '2006-04-01 00:00:00'::date and '2006-04-10 00:00:00'::date GROUP BY clients2.id::int,name::text,ds ORDER BY name,ds;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Sort (cost=132056.49..132544.72 rows=195292 width=36)
Sort Key: clients2.name, to_char(date_trunc('day'::text, iptables."second"), 'DD'::text)
-> GroupAggregate (cost=103396.11..109739.93 rows=195292 width=36)
-> Sort (cost=103396.11..104371.93 rows=390331 width=36)
Sort Key: clients2.id, clients2.name, to_char(date_trunc('day'::text, iptables."second"), 'DD'::text)
-> Hash Join (cost=56.63..42555.41 rows=390331 width=36)
Hash Cond: ("outer".dest = "inner".ip)
-> Index Scan using idx_second on iptables (cost=0.00..34692.16 rows=390331 width=27)
Index Cond: (("second" >= '2006-04-01 00:00:00'::timestamp without time zone) AND ("second" <= '2006-04-10 00:00:00'::timestamp without time zone))
-> Hash (cost=54.26..54.26 rows=947 width=31)
-> Hash Join (cost=20.59..54.26 rows=947 width=31)
Hash Cond: ("outer".id = "inner".id)
-> Seq Scan on net_addr (cost=0.00..19.47 rows=947 width=15)
-> Hash (cost=18.47..18.47 rows=847 width=20)
-> Seq Scan on clients2 (cost=0.00..18.47 rows=847 width=20)
(15 rows)
...
Рейтинг: 0 / 0
27.04.2006, 10:09
    #33693440
AlexTheRaven
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
Память проверяли?
В файле postgresql.conf есть раздел resourse usage->memory. В нём есть параметры work_mem, maintenance_work_mem, max_stack_depth. По умолчанию там стоят до смешного маленькие значения. Попробуйте увеличить их раз в 10-20.
...
Рейтинг: 0 / 0
27.04.2006, 10:15
    #33693458
Алексей Ключников
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
Посмотреть в сторону Partitioning.
http://www.postgresql.org/docs/8.1/interactive/ddl-partitioning.html
Очень помогает.
...
Рейтинг: 0 / 0
27.04.2006, 10:34
    #33693528
Funny_Falcon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
А explain analyze можно? И оборачивай explain как сырцы (кнопочка SRC при написании топика).
...
Рейтинг: 0 / 0
27.04.2006, 12:15
    #33693979
postt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
EXPLAIN ANALYZE SELECT sum(bytes),to_char(date_trunc('day',second),'DD'),name,clients2.id FROM iptables,net_addr,clients2 WHERE ((net_addr.ip=iptables.dest) and (clients2.id=net_addr.id)) and second  BETWEEN '2006-04-01' and '2006-04-30' GROUP BY clients2.id,name,to_char(date_trunc('day',second),'DD')  ORDER BY name,to_char(date_trunc('day',second),'DD');
                                                                                  QUERY PLAN                                                                                                                
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost= 378593 . 39 .. 380048 . 91  rows= 582207  width= 36 ) (actual time= 48179 . 569 .. 48192 . 531  rows= 21107  loops= 1 )
   Sort Key: clients2.name, to_char(date_trunc('day'::text, iptables."second"), 'DD'::text)
   ->  GroupAggregate  (cost= 284606 . 30 .. 303518 . 66  rows= 582207  width= 36 ) (actual time= 43915 . 575 .. 47847 . 327  rows= 21107  loops= 1 )
         ->  Sort  (cost= 284606 . 30 .. 287515 . 46  rows= 1163664  width= 36 ) (actual time= 43915 . 373 .. 44749 . 620  rows= 606917  loops= 1 )
               Sort Key: clients2.id, clients2.name, to_char(date_trunc('day'::text, iptables."second"), 'DD'::text)
               ->  Hash Join  (cost= 56 . 63 .. 126750 . 74  rows= 1163664  width= 36 ) (actual time= 8 . 044 .. 11124 . 963  rows= 606917  loops= 1 )
                     Hash Cond: ("outer".dest = "inner".ip)
                     ->  Index Scan using idx_second on iptables  (cost= 0 . 00 .. 103420 . 83  rows= 1163664  width= 27 ) (actual time= 0 . 187 .. 3623 . 816  rows= 1191591  loops= 1 )
                           Index Cond: (("second" >= '2006-04-01 00:00:00'::timestamp without time zone) AND ("second" <= '2006-04-30 00:00:00'::timestamp without time zone))
                     ->  Hash  (cost= 54 . 26 .. 54 . 26  rows= 947  width= 31 ) (actual time= 7 . 620 .. 7 . 620  rows= 0  loops= 1 )
                           ->  Hash Join  (cost= 20 . 59 .. 54 . 26  rows= 947  width= 31 ) (actual time= 2 . 544 .. 6 . 386  rows= 948  loops= 1 )
                                 Hash Cond: ("outer".id = "inner".id)
                                 ->  Seq Scan on net_addr  (cost= 0 . 00 .. 19 . 47  rows= 947  width= 15 ) (actual time= 0 . 004 .. 0 . 994  rows= 948  loops= 1 )
                                 ->  Hash  (cost= 18 . 47 .. 18 . 47  rows= 847  width= 20 ) (actual time= 2 . 383 .. 2 . 383  rows= 0  loops= 1 )
                                       ->  Seq Scan on clients2  (cost= 0 . 00 .. 18 . 47  rows= 847  width= 20 ) (actual time= 0 . 016 .. 1 . 389  rows= 849  loops= 1 )
 Total runtime:  48221 . 441  ms
(записей:  16 )

Когда Postgres считает суммы в этом запросе,он сканирует всю таблицу или только часть,ограниченную датой.Если эту часть,то имеет смысл создать Partitioning,а если нет,то не знаю чем он поможет.
В БД сейчас около 10 млн записей,но число постоянно растет.
...
Рейтинг: 0 / 0
27.04.2006, 14:03
    #33694463
Алексей Ключников
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
Партиции можно сделать по клиентам.

А кто что скажет по партициям например по подсетям? :)
...
Рейтинг: 0 / 0
28.04.2006, 10:56
    #33696610
Funny_Falcon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
Я думаю: вначале группируй по iptables.dest, а потом связывай с клиентами:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
SELECT sum(b.bytes), to_char(day, 'DD'), cl.name, cl.id
FROM (
SELECT sum(bytes) as bytes,date_trunc('day',second) as day, dest FROM iptables
WHERE second BETWEEN '2006-04-01' and '2006-04-30'
GROUP BY dest, date_trunc('day', second)
) b
JOIN net_addr na ON na.ip = b.dest
JOIN clients2 cl ON na.id = cl.id
GROUP BY cl.id, cl.name, day
ORDER BY name, day

А значения work_mem и shared_buffers в postgresql.conf каковы (как правильно заметил AlexTheRaven)? Shared Buffers - в твоем случае наверно под гектар стоит выделить ( - на сколько за месяц объем данных увеличивается - чтобы сразу весь месяц в памяти держать) (и вообще: какая железка/ось?).
...
Рейтинг: 0 / 0
28.04.2006, 11:11
    #33696685
LeXa NalBat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
posttЧто нужно сделать,чтобы оптимизировать работы Postgres на огромных таблицах. Например долго выполняется запрос вида ( причем операции с индексом тоже работают долго)Нужно не работать с огромными таблицами. Например, если у вас в таблицу iptables добавляются строки с second~=now() и впоследствии не изменяются и не удаляются, то можно один раз в сутки чуть позже полуночи делать "insert into daily_stat_1 as select clients2.id, clients2.name, sum(bytes)::double precision as bytes, to_char(date_trunc('day',second),'DD')::text AS ds from ... where second between now()-'1 day' and now()" и затем делать выборки из этой таблицы.

postt
Код: plaintext
1.
2.
3.
4.
5.
   ->  GroupAggregate  (cost=284606.30..303518.66 rows=582207 width=36) (actual time=43915.575..47847.327 rows=21107 loops=1)
         ->  Sort  (cost=284606.30..287515.46 rows=1163664 width=36) (actual time=43915.373..44749.620 rows=606917 loops=1)
               Sort Key: clients2.id, clients2.name, to_char(date_trunc('day'::text, iptables."second"), 'DD'::text)
...
                     ->  Index Scan using idx_second on iptables  (cost=0.00..103420.83 rows=1163664 width=27) (actual time=0.187..3623.816 rows=1191591 loops=1)
                           Index Cond: (("second" >= '2006-04-01 00:00:00'::timestamp without time zone) AND ("second" <= '2006-04-30 00:00:00'::timestamp without time zone))

Когда Postgres считает суммы в этом запросе,он сканирует всю таблицу или только часть,ограниченную датой.В сортировку и группировку приходит 600 тыс строк - с учетом ограничения по дате, которое накладывается ранее при IndexScan.

P.S.: кстати, из миллиона с лишним строк полученных в IndexScan остаются только 600 тыс. оставшиеся не тарифицируются? это ошибка?

Funny_FalconЯ думаю: вначале группируй по iptables.dest, а потом связывай с клиентами:Я уже давал ему такой совет. http://sql.ru/forum/actualthread.aspx?tid=268827#2453909

Но здесь принципиального ускорения по-моему можно ожидать лишь избавившись от сортировки работающей 36 секунд, что составляет 80% от времени выполнения запроса. Но тогда придется пробегать все строки в порядке dest и фильтровать их по second? Хотя можно попобовать HashJoin, такой совет я тоже давал. http://sql.ru/forum/actualthread.aspx?tid=268827#2444761
...
Рейтинг: 0 / 0
28.04.2006, 11:52
    #33696910
AlexTheRaven
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
LeXa NalBat
Но здесь принципиального ускорения по-моему можно ожидать лишь избавившись от сортировки работающей 36 секунд, что составляет 80% от времени выполнения запроса.
Теоретически можно построить индекс, в котором строки будут перечисляться в заранее определённом порядке, и при выборке вместо того, чтобы устраивать новую сортировку, просто пользоваться этим индексом. Как это реализовано в Postgres и реализовано ли вообще - не знаю, но можно посмотреть в этом направлении.
...
Рейтинг: 0 / 0
28.04.2006, 11:56
    #33696929
LeXa NalBat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
AlexTheRaven LeXa NalBat
Но здесь принципиального ускорения по-моему можно ожидать лишь избавившись от сортировки работающей 36 секунд, что составляет 80% от времени выполнения запроса.Теоретически можно построить индекс, в котором строки будут перечисляться в заранее определённом порядке, и при выборке вместо того, чтобы устраивать новую сортировку, просто пользоваться этим индексом. Как это реализовано в Postgres и реализовано ли вообще - не знаю, но можно посмотреть в этом направлении.Если ограничения по second заранее неизвестны, то есть нужно чтобы быстро работали запросы "where second between A and B group by dest" и "where second between C and D group by dest", то такого индекса по-меому построить нельзя.
...
Рейтинг: 0 / 0
28.04.2006, 13:52
    #33697397
Funny_Falcon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
Можно для начала поменять местами dest и date_trunc
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
SELECT sum(b.bytes), to_char(day, 'DD'), cl.name, cl.id
FROM (
SELECT sum(bytes) as bytes,date_trunc('day',second) as day, dest FROM iptables
WHERE second BETWEEN '2006-04-01' and '2006-04-30'
GROUP BY date_trunc('day', second), dest
) b
JOIN net_addr na ON na.ip = b.dest
JOIN clients2 cl ON na.id = cl.id
GROUP BY cl.id, cl.name, day
ORDER BY name, day

Если second имеет тип timestamp (без tz), то можно построить индекс:
Код: plaintext
1.
2.
create index iptables_ix_day_dest on iptables
( (date_trunc('day',second)), dest);
и тогда
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
SELECT sum(b.bytes), to_char(day, 'DD'), cl.name, cl.id
FROM (
SELECT sum(bytes) as bytes,date_trunc('day',second) as day, dest FROM iptables
WHERE date_trunc('day', second) BETWEEN '2006-04-01' and '2006-04-30'
GROUP BY date_trunc('day', second), dest
) b
JOIN net_addr na ON na.ip = b.dest
JOIN clients2 cl ON na.id = cl.id
GROUP BY cl.id, cl.name, day
ORDER BY name, day
...
Рейтинг: 0 / 0
28.04.2006, 14:01
    #33697426
postt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
600 тыс. из 1.2 млн возвращается из-за того,что это только строчки,соответствующие входящему трафику,а есть еще исходящий.Не совсем правильно нужно два поля в одной строке,но пока еще не сделал.
Об оборудовании:
cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 15
model : 4
model name : Intel(R) Celeron(R) CPU 2.26GHz
stepping : 1
cpu MHz : 2260.319
cache size : 256 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 5
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe pni monitor ds_cpl cid
bogomips : 4508.87
Памяти 512Мб.
OC ALTLinux 2.4.
...
Рейтинг: 0 / 0
29.04.2006, 20:10
    #33699287
postt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
EXPLAIN ANALYZE SELECT sum(b.bytes), to_char(day, 'DD'), cl.name, cl.id FROM ( SELECT sum(bytes) as bytes,date_trunc('day',second) as day, source FROM iptables WHERE date_trunc('day', second) BETWEEN '2006-04-01' and '2006-04-30' GROUP BY date_trunc('day', second), source ) b JOIN net_addr na ON na.ip = b.source JOIN clients2 cl ON na.id = cl.id GROUP BY cl.id, cl.name, day ORDER BY name, day;
                                                                                                              QUERY PLAN                                                                                                      
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost= 99176 . 61 .. 99207 . 69  rows= 12432  width= 36 ) (actual time= 11016 . 955 .. 11030 . 140  rows= 21912  loops= 1 )
   Sort Key: cl.name, b."day"
   ->  HashAggregate  (cost= 98268 . 96 .. 98331 . 12  rows= 12432  width= 36 ) (actual time= 10441 . 709 .. 10549 . 880  rows= 21912  loops= 1 )
         ->  Hash Join  (cost= 56 . 72 .. 98144 . 64  rows= 12432  width= 36 ) (actual time= 193 . 302 .. 10328 . 684  rows= 25909  loops= 1 )
               Hash Cond: ("outer".source = "inner".ip)
               ->  Subquery Scan b  (cost= 0 . 00 .. 97901 . 44  rows= 12432  width= 48 ) (actual time= 185 . 448 .. 10180 . 087  rows= 25997  loops= 1 )
                     ->  GroupAggregate  (cost= 0 . 00 .. 97777 . 12  rows= 12432  width= 27 ) (actual time= 185 . 442 .. 10108 . 389  rows= 25997  loops= 1 )
                           ->  Index Scan using iptables_ix_day_source on iptables  (cost= 0 . 00 .. 97530 . 55  rows= 24588  width= 27 ) (actual time= 0 . 258 .. 7592 . 128  rows= 1231689  loops= 1 )
                                 Index Cond: ((date_trunc('day'::text, "second") >= '2006-04-01 00:00:00'::timestamp without time zone) AND (date_trunc('day'::text, "second") <= '2006-04-30 00:00:00'::timestamp without time zone))
               ->  Hash  (cost= 54 . 35 .. 54 . 35  rows= 949  width= 31 ) (actual time= 7 . 525 .. 7 . 525  rows= 0  loops= 1 )
                     ->  Hash Join  (cost= 20 . 62 .. 54 . 35  rows= 949  width= 31 ) (actual time= 2 . 449 .. 6 . 367  rows= 952  loops= 1 )
                           Hash Cond: ("outer".id = "inner".id)
                           ->  Seq Scan on net_addr na  (cost= 0 . 00 .. 19 . 49  rows= 949  width= 15 ) (actual time= 0 . 052 .. 1 . 101  rows= 952  loops= 1 )
                           ->  Hash  (cost= 18 . 50 .. 18 . 50  rows= 850  width= 20 ) (actual time= 2 . 294 .. 2 . 294  rows= 0  loops= 1 )
                                 ->  Seq Scan on clients2 cl  (cost= 0 . 00 .. 18 . 50  rows= 850  width= 20 ) (actual time= 0 . 017 .. 1 . 341  rows= 854  loops= 1 )
 Total runtime:  11069 . 723  ms
(çàïèñåé:  16 )
Спасибо.Стало значительно быстрее работать.
...
Рейтинг: 0 / 0
02.05.2006, 10:47
    #33701017
Funny_Falcon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
Код: plaintext
1.
2.
                           ->  Index Scan using iptables_ix_day_source on iptables  (cost= 0 . 00 .. 97530 . 55  rows= 24588  width= 27 ) (actual time= 0 . 258 .. 7592 . 128  rows= 1231689  loops= 1 )
                                 Index Cond: ((date_trunc('day'::text, "second") >= '2006-04-01 00:00:00'::timestamp without time zone) AND (date_trunc('day'::text, "second") <= '2006-04-30 00:00:00'::timestamp without time zone))
Видимо здесь постгрес не использует второй столбец в индексе (source). Поэтому имеет смысл сделать индекс без него - меньше места на диске будет занимать => меньше чтений диска.
А если нужно быстро делать выборку по клиенту, то для PostgreSQL8.1 имеют смысл еще два отдельных индекса - по source и по dest.
...
Рейтинг: 0 / 0
02.05.2006, 11:28
    #33701149
LeXa NalBat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
Funny_FalconВидимо здесь постгрес не использует второй столбец в индексе (source).Это поле используется, но не для выборки (фильтрации) по индексу, а благодаря ему отсутствует пересортировка перед GroupAggregate.
...
Рейтинг: 0 / 0
02.05.2006, 13:37
    #33701635
Funny_Falcon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация Postgres для огромных таблиц
LeXa NalBatЭто поле используется, но не для выборки (фильтрации) по индексу, а благодаря ему отсутствует пересортировка перед GroupAggregate.
Был неправ, исправлюсь.
...
Рейтинг: 0 / 0
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Оптимизация Postgres для огромных таблиц / 16 сообщений из 16, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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