Массовая вставка данных в SQLQuery, получить итоговый запрос

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Ism
энтузиаст
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Массовая вставка данных в SQLQuery, получить итоговый запрос

Сообщение Ism »

Привет
Необходимо вставить сразу более 20000 записей. Но вот проблема, SQLQuery в режиме CachedUpdates:=true по ApplyUpdates применяет вставку по одному insert, что гораздо медленнее , чем просто бросить скрипт вставки на сервер и там выполнить
Сервер MySql
Есть ли возможность получить скрипт вставки из DataSet не отправляя данные, а потом отправить на сервер через ExecuteDirect ?

Можно конечно сформировать запрос вручную, но это неудобно
Padre_Mortius
энтузиаст
Сообщения: 1265
Зарегистрирован: 29.05.2007 17:38:07
Откуда: Спб

Сообщение Padre_Mortius »

данные вы откуда берете?

если из таблицы. то вроде была возможность использовать что-то вроде

Код: Выделить всё

insert into table select * from table2 where ...
Ism
энтузиаст
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Сообщение Ism »

Padre_Mortius писал(а):данные вы откуда берете?

если из таблицы. то вроде была возможность использовать что-то вроде

Код: Выделить всё

insert into table select * from table2 where ...

Тут все проблематично, данные берутся из одной базы(не MySql) и сливаются в другую, поэтому единственный вариант брать запись из одной базы и бросать в другую.
Ускорить можно только бросая пакетами, и как заставить SQLQuery это делать непонятно
Padre_Mortius
энтузиаст
Сообщения: 1265
Зарегистрирован: 29.05.2007 17:38:07
Откуда: Спб

Сообщение Padre_Mortius »

Можно попробовать несколько Insert-запросов обрамить в

Код: Выделить всё

BEGIN TRANSACTION;
INSERT ...;
INSERT ...;
COMMIT TRANSACTION;

Я делал похожим образом для sqlite, но там пользовался их API, а не SQLQuery (причину уже не помню)
Ism
энтузиаст
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Сообщение Ism »

Padre_Mortius писал(а):Можно попробовать несколько Insert-запросов обрамить в

Код: Выделить всё

BEGIN TRANSACTION;
INSERT ...;
INSERT ...;
COMMIT TRANSACTION;

Я делал похожим образом для sqlite, но там пользовался их API, а не SQLQuery (причину уже не помню)


В этом проблемы нет, проблема в том, что один insert на строку даже в транзакции медленно передается и выполняется,
Единственный вариант это
insert ...
values
(1,2,3)
(6,7,8)

И так далее, если бросить такой запрос на сервер одной командой, то это будет на порядок быстрее

Просто SQLQuery не умеет бросать на сервер insert скопом, похоже придется вручную формировать
Padre_Mortius
энтузиаст
Сообщения: 1265
Зарегистрирован: 29.05.2007 17:38:07
Откуда: Спб

Сообщение Padre_Mortius »

Если к TSQLQuery подключен TTransactionSQL, то должно очень быстро выполняться...
Ism
энтузиаст
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Сообщение Ism »

Padre_Mortius писал(а):Если к TSQLQuery подключен TTransactionSQL, то должно очень быстро выполняться...

Дело не в транзакции, а в том, что по одному insert медленнее, чем вариант указанный выше
Padre_Mortius
энтузиаст
Сообщения: 1265
Зарегистрирован: 29.05.2007 17:38:07
Откуда: Спб

Сообщение Padre_Mortius »

Разве при оформлении в явную транзакцию сервер должен ее разбивать эту транзакцию на более мелкие коммиты? К транзакции вроде должен применяться только один коммит в конце если нет ошибок, или rollback если произошла ошибка. И параметра CachedUpdates у TSQLQuery не нашел (Лазарь 1.1 из свн)

Добавлено спустя 5 минут 38 секунд:
Re: Массовая вставка данных в SQLQuery, получить итоговый запрос
Поправлю себя. Похоже разбитие транзакции это фича MySQL при включенном параметре autocommit=1 при использовании движка InnoDB http://dev.mysql.com/doc/refman/5.5/en/commit.html
Ism
энтузиаст
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Сообщение Ism »

Извиняюсь хотел упростить.
У меня myisam и компоненты zeos , в myisam вообще транзакций нет
Вообще похоже массовая вставка это фича только mysql, а компоненты сделаны чтоб работать со всеми базами
Vadim
долгожитель
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Сообщение Vadim »

Ism
А если скрипт, как посоветовал Padre_Mortius, закидывать с помощью компонента TZSQLProcessor?
Ism
энтузиаст
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Сообщение Ism »

Vadim писал(а):Ism
А если скрипт, как посоветовал Padre_Mortius, закидывать с помощью компонента TZSQLProcessor?

Именно, так я и делал, но это очень неудобно формировать запрос складывая запрос в строку.
Гораздо правильное присваивать через
SQLQuery.insert
FieldByName('').text:='123'
SQLQuery.Post

Но это оказывается слишком медленно , для огромных объемов. Похоже выход viewtopic.php?f=23&t=8816

TZSQLProcessor все равно выполняет SQL команды поочередно , отправляя на сервер по одной
Padre_Mortius
энтузиаст
Сообщения: 1265
Зарегистрирован: 29.05.2007 17:38:07
Откуда: Спб

Сообщение Padre_Mortius »

Ism, а если отказаться от Zeos и попробовать родными компонентами Лазаря? Есть подозрение, что это специфика именно компонентов Zeos.
Frolik
постоялец
Сообщения: 275
Зарегистрирован: 18.08.2011 11:52:32

Сообщение Frolik »

Единственный вариант это
insert ...
values
(1,2,3)
(6,7,8)

И так далее, если бросить такой запрос на сервер одной командой, то это будет на порядок быстрее

Просто SQLQuery не умеет бросать на сервер insert скопом, похоже придется вручную формировать


Я не понял, почему не подошел этот вариант?
Zeos прекрасно справляется с такими запросами. В моем проекте по 2-3 тысячи строк таким образом записываются. Но поля в таблице только integer.
Vadim
долгожитель
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Сообщение Vadim »

Ism писал(а):Именно, так я и делал, но это очень неудобно формировать запрос складывая запрос в строку.

А зачем в строку?
Var
zp: TZSQLProcessor;

zp.Script.LoadFromFile()
или
For i:=1 To Кол-во_запросов Do
zp.Script.Add('INSERT ...')
а потом
zp.Execute;
Ism
энтузиаст
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Сообщение Ism »

Vadim писал(а):
Ism писал(а):Именно, так я и делал, но это очень неудобно формировать запрос складывая запрос в строку.

А зачем в строку?
Var
zp: TZSQLProcessor;

zp.Script.LoadFromFile()
или
For i:=1 To Кол-во_запросов Do
zp.Script.Add('INSERT ...')
а потом
zp.Execute;

Я писал выше, ZSQLProcessor выполняет insert по одному. В случае вставки скопом достаточно ExecuteDirect, тогда строка одним пакетом отправляется на сервер и только там разбирается.Mysql гораздо быстрее разбирается с данными, чем датасет Так можно вставлять десятки тысяч строк за раз и время вставки будет в десятки раз меньше
Ответить