Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / INSERT в большую БД / 14 сообщений из 14, страница 1 из 1
06.03.2006, 10:47
    #33583370
mxlPostgres
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
INSERT в большую БД
Есть скрипт на Си,который читает файл и из него пишет в БД.При малом кол-ве записей в базе читает довольно быстро,но при кол-ве записей около 1 млн INSERTы выполняются медленно.
Как можно ускорить вставку записей.
Привожу запросы:
sprintf(str,"SELECT bytes,dest,date_last,time_last FROM iptables_last WHERE dest='%s' and source='0.0.0.0/0'",dest);
res=PQexec(conn,str);
bytes_new=atof(bytes)-atof(PQgetvalue(res,0,0));
sprintf(str,"INSERT INTO iptables (bytes,prot,source,dest,date_second,time_second,date_first,time_first) \
VALUES ('%f','%s','%s','%s','%s','%s','%s','%s'); \
UPDATE iptables_last SET bytes='%s',date_last='%s',time_last='%s' \
WHERE dest='%s';",bytes_new,prot,source,dest,PQgetvalue(res,0,2),PQgetvalue(res,0,3),dat_st_,time,bytes,dat_st_,time,dest);
res = PQexec(conn,str);
...
Рейтинг: 0 / 0
06.03.2006, 11:45
    #33583566
mxlPostgres
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
INSERT в большую БД
Хотя может это нормальная ситуация,но что тогда будет с БД при числе записей в 20-30 млн. и более???Я думаю так быть не должно и что-то можно оптимизировать,если нужна более подробная информация,говорите какая.
EXPLAIN ANALYZE INSERT INTO iptables_last (bytes,prot,source,dest,date_last,time_last) VALUES (0,'','1.1.1.1','1.1.1.1','2006-01-01','01:01:01');
QUERY PLAN
--------------------------------------------------------------------------------------
Result (cost=0.00..0.01 rows=1 width=0) (actual time=25.859..25.861 rows=1 loops=1)
Total runtime: 150.591 ms
Таблица:
\d iptables
Table "public.iptables"
Column | Type | Modifiers
-------------+------------------------+------------------------------------------------------------
id_iptables | integer | not null default nextval('iptables_id_iptables_seq'::text)
bytes | double precision |
prot | text |
source | inet |
dest | inet |
date_second | date |
time_second | time without time zone |
date_first | date |
time_first | time without time zone |
Indexes:
"iptables_pkey" primary key, btree (id_iptables)
"idx_ipt_dest" btree (dest)
"idx_ipt_src" btree (source)
...
Рейтинг: 0 / 0
06.03.2006, 13:41
    #33584035
.Guest
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
INSERT в большую БД
Может, формировать готовый файл и заливать его сразу в базу при помощи COPY FROM?
...
Рейтинг: 0 / 0
06.03.2006, 13:53
    #33584088
mxlPostgres
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
INSERT в большую БД
Идея неплохая,но файл нестандартный и его нужно дополнительно формировать.Можно поподробнее как работает COPY?Попробую этот вариант и сравню скорость.Все же интересно почему скорость при росте числа записей заметно падает.
...
Рейтинг: 0 / 0
06.03.2006, 13:58
    #33584120
.Guest
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
INSERT в большую БД
Файл для COPY нужно формировать самому. Формат (разделители и прочее) указываешь в самом операторе COPY. Проще всего, наверное, формировать подобие CSV (comma separated values). Почитай доки по COPY там все несложно.
Ускорение будет в том числе и от того, что все данные из файла будут заливаться в рамках одной транзакции.
...
Рейтинг: 0 / 0
06.03.2006, 16:34
    #33584736
Funny_Falcon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
INSERT в большую БД
Я в С и libpq не силен. Ты обрамляешь INSERT-ы в транзакцию? (лучше, я думаю, кусками по 1000 INSERT-ов) Есть ли возможность использовать PREPARED запросы?
...
Рейтинг: 0 / 0
06.03.2006, 19:44
    #33585269
kolobok0
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
INSERT в большую БД
mxlPostgresЕсть скрипт на Си,который читает файл и из него пишет в БД.При малом кол-ве записей в базе читает довольно быстро,но при кол-ве записей около 1 млн INSERTы выполняются медленно.....

глупые вопросы...
1) делаете ли Вы после каждого PQexec вызов PQclear ?
2) одинаково ли время выполнения данной вставки локально, удалённо ?
3) пробовали ли Вы вставлять конец транзакции после 1000 (например) записей ?


с уважением
(круглый)
...
Рейтинг: 0 / 0
06.03.2006, 20:39
    #33585347
mxlPostgres
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
INSERT в большую БД
kolobok0 mxlPostgresЕсть скрипт на Си,который читает файл и из него пишет в БД.При малом кол-ве записей в базе читает довольно быстро,но при кол-ве записей около 1 млн INSERTы выполняются медленно.....

глупые вопросы...
1) делаете ли Вы после каждого PQexec вызов PQclear ?
2) одинаково ли время выполнения данной вставки локально, удалённо ?
3) пробовали ли Вы вставлять конец транзакции после 1000 (например) записей ?


с уважением
(круглый)
sprintf(str," BEGIN INSERT INTO iptables (bytes,prot,source,dest,date_second,time_second,date_first,time_first) \
VALUES ('%f','%s','%s','%s','%s','%s','%s','%s'); \
UPDATE iptables_last SET bytes='%s',date_last='%s',time_last='%s' \
WHERE dest='%s'; COMMIT ",bytes_new,prot,source,dest,PQgetvalue(res,0,2),PQgetvalue(res,0,3),dat_st_,time,bytes,dat_st_,time,dest);
Вставил begin..commit,чтобы исключить потерю данных.COPY не подойдет из-за критичности к целостности данных,нужны транзакции.
PQclear не выполняется,а разве можно этим ускорить процесс??
...
Рейтинг: 0 / 0
06.03.2006, 21:04
    #33585384
mxlPostgres
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
INSERT в большую БД
Funny_FalconЯ в С и libpq не силен. Ты обрамляешь INSERT-ы в транзакцию? (лучше, я думаю, кусками по 1000 INSERT-ов) Есть ли возможность использовать PREPARED запросы?
Для чего PREPARED?Сейчас объединю дату и время в одну колонку.Думаю,будет чуть быстрее.
...
Рейтинг: 0 / 0
06.03.2006, 21:16
    #33585398
-me-
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
INSERT в большую БД
mxlPostgres
sprintf(str," BEGIN INSERT INTO iptables (bytes,prot,source,dest,date_second,time_second,date_first,time_first) \
VALUES ('%f','%s','%s','%s','%s','%s','%s','%s'); \
UPDATE iptables_last SET bytes='%s',date_last='%s',time_last='%s' \
WHERE dest='%s'; COMMIT ",bytes_new,prot,source,dest,PQgetvalue(res,0,2),PQgetvalue(res,0,3),dat_st_,time,bytes,dat_st_,time,dest);
Вставил begin..commit,чтобы исключить потерю данных.COPY не подойдет из-за критичности к целостности данных,нужны транзакции.
PQclear не выполняется,а разве можно этим ускорить процесс??
1. Та не туды транзакции :)
Стоит поставить раз 1000 - 10000 блоков SELECT/INSERT,
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
 if ( 0  == rows_processed_count %  10000 ) 
{
  PQexec(conn, "COMMIT");
  PQexec(conn, "BEGIN");
}
// тут ваш код
++rows_processed_count ;
2. А нафига SELECT каждый раз? Я бы скорее использовал внутрипрограммный кеш, например хэш для значений iptables_last где dest - будет ключом (в PERL - это было бы плевое дело), и после всех INSERT'ов провел бы пачку UPDATE iptables_last.

P.S. О бэкапах не забываем :)
...
Рейтинг: 0 / 0
07.03.2006, 09:14
    #33585845
Funny_Falcon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
INSERT в большую БД
mxlPostgres Для чего PREPARED?Сейчас объединю дату и время в одну колонку.Думаю,будет чуть быстрее.
Чтобы серваку не надо было каждый раз полностью парсить инсерты и апдейты и строить для них запросы. PREPARED - уже построенный план запроса и только данные подставляй.
Но основное - это все-таки транзакции. Если каждый инсерт в транзакции, то это миллион коммитов, а коммит не такая уж и дешевая операция. Если пачками по 1000 - то всего 1000 коммитов. Если явно транзакции не указываешь и автокоммит включен(он включен по умолчанию), то снова коммит на каждый инсерт - миллион коммитов.
...
Рейтинг: 0 / 0
07.03.2006, 13:10
    #33586669
Opilki_Inside
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
INSERT в большую БД
ИМХО, лучше всего в такой ситуации использовать именно COPY FROM STDIN
хорошо, что ты используешь libpq

Работает все давольно просто и быстро... более быстрого способа занесения данных из файла в БД ты не найдешь

Сначала выполняешь запрос типа
Код: plaintext
copy tablename(field1,field2,field3) from stdin using delimiters '#' with null as '<NULL>';
Потом начинаешь копировать данные... не важно откуда ты их берешь, в любом случае - приводишь к строке...

Код: plaintext
PQputline(conn, "data1#data2#data3")

А потом выполняешь команду завершения копирования
PQputline(db->connection(), ru("\\.\n").local8Bit());
int res = PQendcopy(db->connection());
if (res!=0)
{ошибка}
...
Рейтинг: 0 / 0
07.03.2006, 16:41
    #33587326
ilejn
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
INSERT в большую БД
mxlPostgresЕсть скрипт на Си,который читает файл и из него пишет в БД.При малом кол-ве записей в базе читает довольно быстро,но при кол-ве записей около 1 млн INSERTы выполняются медленно.
Как можно ускорить вставку записей.
Привожу запросы:
sprintf(str,"SELECT bytes,dest,date_last,time_last FROM iptables_last WHERE dest='%s' and source='0.0.0.0/0'",dest);
res=PQexec(conn,str);
bytes_new=atof(bytes)-atof(PQgetvalue(res,0,0));
sprintf(str,"INSERT INTO iptables (bytes,prot,source,dest,date_second,time_second,date_first,time_first) \
VALUES ('%f','%s','%s','%s','%s','%s','%s','%s'); \
UPDATE iptables_last SET bytes='%s',date_last='%s',time_last='%s' \
WHERE dest='%s';",bytes_new,prot,source,dest,PQgetvalue(res,0,2),PQgetvalue(res,0,3),dat_st_,time,bytes,dat_st_,time,dest);
res = PQexec(conn,str);

1. На Си не бывает скриптов.
2. В приведенном фрагменте, насколько я понимаю, содержится ошибка - не делается PQclear, что явно должно приводить к неприятным последствиям.
3. Как там дела с транзакциями?
...
Рейтинг: 0 / 0
07.03.2006, 19:31
    #33587652
kolobok0
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
INSERT в большую БД
mxlPostgres....PQclear не выполняется,а разве можно этим ускорить процесс??

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

первое как мне икаеться может быть по разным причинам...
например нет освобождения ресурсов (отсюда косвенно вопрос про PQclear).. Либо не закрываються транзакции (или накапливаються в рамках одной транзакции).. Чтобы отсеять проблемы клиента от сервера - был вопрос про различные тук-тук к серваку...Локально, или удалённо.. Соответственно если ничего не меняеться - проблема сервака...

накопление отложеных операций изменений по таблицам - пока не знаю, что сказать...вопросы тюнинга попахивает...

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

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

с уважением
(круглый)
...
Рейтинг: 0 / 0
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / INSERT в большую БД / 14 сообщений из 14, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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