#sqlite #tcl
#sqlite #tcl
Вопрос:
Я новичок в tcl. Я подключился к базе данных SQLite.
У меня есть около 100 000 записей, которые я хочу вставить в базу данных после вычисления. Я использую следующую команду для вставки записей в базу данных 100 000 раз.
Я уверен, что здесь я делаю что-то не так. Какой был бы подходящий способ сделать это?
Для вставки:
db eval {insert into table values(value1,value2,value3,value4)}
Для извлечения мне приходится выполнять операцию выбора не менее 1000 раз, все происходит ужасно медленно:
db eval {select x as x, y as y from table} {
set z [expr $z $x $y]
}
Комментарии:
1. Вы помещаете
db eval {select ...} {...}
в цикл, или в результате просто обрабатывается тысяча строк?
Ответ №1:
По умолчанию каждая вставка представляет собой одну транзакцию. Это происходит очень медленно. Вы можете сгруппировать свои вставки в отдельные транзакции, скажем, из 100 вставок, и значительно ускорить процесс.
db eval { BEGIN TRANSACTION }
... do some insertions ...
db eval { END TRANSACTION }
или
db transaction {
... do some insertions ...
}
Из коробки SQLITE чрезвычайно безопасен, но довольно медленный. Если вы знаете, что делаете, и готовы рисковать повреждением базы данных при сбое диска, то вы можете выполнить несколько оптимизаций, которые обеспечат впечатляющее повышение скорости.
В частности:
- Отключить синхронизацию (PRAGMA synchronous = ВЫКЛ.;)
- Групповая запись в транзакции
- Индексные таблицы
- Использовать базу данных в памяти
Если вы не изучили все это, то, скорее всего, работаете во много раз медленнее, чем могли бы.
Комментарии:
1. Это хорошо работает для вставок. Есть ли способ ускорить выбор?
2. В общем, выбор выполняется быстро, что означает меньшую возможность их оптимизации. Вы просмотрели ответ, на который я ссылался? Следующее, что нужно попробовать, это отключить синхронизацию. Но я подозреваю, что это не улучшит выбор.
3. Я просмотрел образец инструкции select, который вы опубликовали. Вы уверены, что узкое место находится в sqlite? Сколько времени требуется TCL для выполнения 1000 раз set z [выражение $ z $ x $ y]?
4. Фактически, открытие файла соответствует созданию соединения (т.е.
db
дескриптору). Тем не менее, транзакции по-прежнему дороги; запуск одной из них в значительной степени эквивалентен блокировке области файла, а ее фиксация соответствует, среди прочего, полной загрузке на диск. Очень дорого! Вывод базы данных из режима автоматической фиксации по умолчанию — огромная победа.5. Интерфейс SQLite от Tcl имеет дополнительную бонусную функцию: поддержку синтаксических транзакций. Используйте следующим образом:
db transaction { ... do some insertions ...}
. Успешное завершение кода приводит к фиксации, генерируемые исключения приводят к откату. Просто.
Ответ №2:
Я не могу ответить на часть вопроса sqlite, потому что я не использовал sqlite несколько лет, но одной из причин снижения производительности является ваше выражение expr. Вам нужно заключить аргументы в скобки для выражения, что должно значительно ускорить эту часть вашего цикла:
set z [expr {$z $x $y}]
Ответ №3:
Да, выполнение одиночных вставок из Tcl в таблицу sql — не самый быстрый способ выполнить то, что вы хотите.
Чтобы ускорить процесс, вы должны записать нужную таблицу во внешний файл и загрузить данные с помощью одной инструкции db.
Вы бы записали данные следующим образом:
set fh [open temp_file w]
set rowid 0
# loop
puts $fh [join [list $value1 $value2 $value3 $value4] t]
# end loop
close $fh
Затем, используя метод копирования, вы можете прочитать все за один раз:
db copy replace values temp_file
А что касается вычисления суммы, я не знаю, почему вы не используете сам sql для выполнения суммирования. В Интернете есть много примеров того, как это сделать. Вот пара примеров. Я полагаю, что ваш оператор sql будет выглядеть примерно так:
db select sum(x y) from table
или, возможно
db select sum(x y) as z from table
Комментарии:
1. Я должен использовать некоторые значения, которые я вычисляю в программе, также со значениями, которые я получаю из таблицы.