Что нового

Функция для отправки данных в базу SQLite - обратный аналог _SQLite_FetchData

veretragna

Как писал, так и работает.
Сообщения
140
Репутация
10
Версия AutoIt: 3.3.12.0

Описание: Нужна функция, аналогичная _SQLite_FetchData, только наоборот - чтобы отправлять данные в базу, повторно используя тот же statement, полученный от _SQLite_Query.

Примечания:

Доброго вечера сообществу.
В процессе исследования функционала UDF SQLite.au3, и сопоставив со своими данными, я узнал, что SQLite позволяет проводить некоторые интересные вещи.
Например, по одному query, полученному от функции _SQLite_Query, можно получить множество данных. Например, так:
Код:
_SQLite_Query(-1, "SELECT Name FROM 'GuildList';", $hQuery)
While 1
	If _SQLite_FetchData($hQuery, $aRow) = $SQLITE_OK Then
		; предпринимаем действия
	Else
		_SQLite_QueryFinalize($hQuery)
		ExitLoop
	EndIf
WEnd


Исследуя примеры использования SQLite на С/С++, я обнаружил, что можно аналогичным образом и отправлять данные, повторно используя тот же statement.

Фрагмент кода на С:
Код:
sprintf(sSQL, "INSERT INTO TTC VALUES (NULL, @RT, @BR, @VR, @ST, @VI, @DT, @TM)");
sqlite3_prepare_v2(db,  sSQL, BUFFER_SIZE, &stmt, &tail);
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &sErrMsg);
pFile = fopen (INPUTDATA,"r");
while (!feof(pFile)) {

    fgets (sInputBuf, BUFFER_SIZE, pFile);

    sqlite3_bind_text(stmt, 1, strtok (sInputBuf, "\t"), -1, SQLITE_TRANSIENT); /* Get Route */
    sqlite3_bind_text(stmt, 2, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);  /* Get Branch */
    sqlite3_bind_text(stmt, 3, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);  /* Get Version */
    sqlite3_bind_text(stmt, 4, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);  /* Get Stop Number */
    sqlite3_bind_text(stmt, 5, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);  /* Get Vehicle */
    sqlite3_bind_text(stmt, 6, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);  /* Get Date */
    sqlite3_bind_text(stmt, 7, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);  /* Get Time */

    sqlite3_step(stmt);     /* Execute the SQL Statement */
    sqlite3_clear_bindings(stmt);   /* Clear bindings */
    sqlite3_reset(stmt);        /* Reset VDBE */

    n++;
}
fclose (pFile);


Буду благодарен, если кто-то реализует такую функцию на AutoIt.
 
Автор
veretragna

veretragna

Как писал, так и работает.
Сообщения
140
Репутация
10
Всё еще актуально.
А если это слишком сложно или невозможно реализовать, я закрою тему.
 
Автор
veretragna

veretragna

Как писал, так и работает.
Сообщения
140
Репутация
10
Ииии снова. Освежу тему.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
veretragna,
У меня, например, нет ни малейшего желания разбираться в коде, написанном на незнакомом мне языке, и, судя по отсутствию ответов, не только у меня. Может проще написать своими словами, что Вы хотите получить?
 
Автор
veretragna

veretragna

Как писал, так и работает.
Сообщения
140
Репутация
10
Объясняю.
Нужна функция, при наличии которой вот этот код будет работать:
Код:
#include <SQLite.au3>
Local $Data[1001][2] ; предположим, что массив уже заполнен данными
_SQLite_Query(-1, 'INSERT INTO Table VALUES (' & $data[1][0] & ', ' & $Data[1][1] &' )', $hQuery)
For $i = 2 to 1001
	Local $attach[2] = [$data[$i][0], $data[$i][1]]
	_SQLite_AttachData($hQuery, $attach) ; этой функции пока не существует. Ее и надо написать.
Next

Func _SQLite_AttachData($hQuery, $Attach)
	; эта функция должна привязывать входные данные к существующему statement'у $hQuery и отправлять данные в базу SQLite.
	; Аналогичный механизм уже задействован в функциях _SQLite_Query() и _SQLite_FetchData(), только там процесс направлен на считывание данных,
	; а эта функция должна осуществлять запись в базу.
	; Механизм работы _SQLite_Query() и _SQLite_FetchData() можно подсмотреть в SQLite.au3,
	; а пример работы той функции, что я хочу получить - в первом сообщении темы, только на С.
EndFunc
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
veretragna [?]
Нужна функция, при наличии которой вот этот код будет работать
А такой вариант добавления массива Вас не устроит?
Код:
#include <SQLite.au3>

Local $s_FileDB = @ScriptDir & '\Test.db', $h_DB, $a_Data[10001][2] = [[10000]], $i_Timer, $aRes, $iRows, $iColumns, _
		$s_Txt = 'BEGIN;DROP TABLE IF EXISTS TEST_TABLE;CREATE TABLE TEST_TABLE ([NUM_INT] INTEGER, [NUM_HEX] TEXT);'

For $i = 1 To $a_Data[0][0]
	$a_Data[$i][0] = $i
	$a_Data[$i][1] = Hex($i, 8)
Next
_SQLite_Startup()
If @error Then Exit 1
$h_DB = _SQLite_Open($s_FileDB)
If @error Then Exit 2
For $i = 1 To $a_Data[0][0]
	$s_Txt &= 'INSERT INTO TEST_TABLE VALUES (' & $a_Data[$i][0] & ', "' & $a_Data[$i][1] & '");'
Next
$s_Txt &= 'COMMIT;'
$i_Timer = TimerInit()
_SQLite_Exec($h_DB, $s_Txt)
If @error Then Exit 3
ConsoleWrite('Insert time: ' & TimerDiff($i_Timer) & ' msec' & @LF)

If _SQLite_GetTable2d($h_DB, 'SELECT * FROM TEST_TABLE;', $aRes, $iRows, $iColumns) Then
	ConsoleWrite('ERROR' & @LF)
Else
	ConsoleWrite('$iRows: ' & $iRows & @LF)
	ConsoleWrite('$iColumns: ' & $iColumns & @LF)
	_ArrayDisplay($aRes, 'TEST_TABLE')
EndIf

_SQLite_Close($h_DB)
_SQLite_Shutdown()
 
Автор
veretragna

veretragna

Как писал, так и работает.
Сообщения
140
Репутация
10
У меня есть в наличии рабочий скрипт, который использует именно эту схему добавления данных.
Этот способ не подходит, нужно именно повторное использование существующего statement'a.
Это обусловлено тем, что при каждом выполнении _SQLite_Exec() или _SQLite_Query() statement создается каждый раз заново, и поэтому мы имеем проигрыш в скорости.
Повторное использование существующего statement'a повышает скорость добавления новых данных в 1,5-2 раза, особенно, если речь идет о десятках тысяч записей.


Добавлено:
Сообщение автоматически объединено:

По крайней мере, если речь идет о С++ - там это доказано.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
veretragna [?]
при каждом выполнении _SQLite_Exec() или _SQLite_Query() statement создается каждый раз заново, и поэтому мы имеем проигрыш в скорости.
В моем примере _SQLite_Exec() вызывается только один раз.
 
Автор
veretragna

veretragna

Как писал, так и работает.
Сообщения
140
Репутация
10
Вы правы, вызывается только 1 раз.
Но речь шла о десятках тысяч запросов за раз, а то и не десятках - кто знает, сколько данных накопится, например, через год работы программы.
В Вашем примере можно легко упереться в технический лимит длины одной строки запроса.
А сколько времени движок SQLite будет его обрабатывать - вообще открытый вопрос, это же могут быть мегабайты только одних запросов.
Намного эффективнее и изящнее все-таки создать один экземпляр query, привязывать к нему данные и отправлять в базу.
При этом, если данные находятся в массиве, мы избегаем просадок скорости, которые наблюдаются при сшивании нескольких строк в одну. Особенно, опять же, если строчек - десятки тысяч.


Добавлено:
Сообщение автоматически объединено:

Ладно, тема закрыта.
Раз уж я взялся серьезно изучать С++, напишу обработку данных в отдельной DLL. Так будет и быстрее, и надежнее.
 

Medic84

Омега
Команда форума
Администратор
Сообщения
1,590
Репутация
341
veretragna [?]
А почему бы не создавать файл DDL, который уже потом отправлять в БД на обработку?
 
Автор
veretragna

veretragna

Как писал, так и работает.
Сообщения
140
Репутация
10
Medic84, а подскажите, как это правильно сделать?
На простеньком примере, так сказать, чтобы понять концепцию.
 

Medic84

Омега
Команда форума
Администратор
Сообщения
1,590
Репутация
341
veretragna [?]
На простеньком примере, так сказать, чтобы понять концепцию.

Код:
#include <SQLite.au3>

Local $Data[1001][2] ; предположим, что массив уже заполнен данными

$sDDLFile = @ScriptDir & "\Transport.ddl"

$hOpen = FileOpen($sDDLFile,256)

FileWrite($hOpen, 'INSERT INTO Table VALUES (' & $Data[1][0] & ', ' & $Data[1][1] &' )' & @CRLF)

For $i = 2 to 1001
    FileWrite($hOpen, 'INSERT INTO Table VALUES (' & $Data[$i][0] & ', ' & $Data[$i][1] &' )'& @CRLF)
Next

FileClose($hOpen)

$sDDL = FileRead($sDDLFile)

If _SQLite_Exec($dbDatabase, $sDDL) = $SQLITE_OK Then  ;Отправляем на обработку и если все нормально, удаляем файл
	FileDelete($sDDLFile)
EndIf
 
Автор
veretragna

veretragna

Как писал, так и работает.
Сообщения
140
Репутация
10
Ваш вариант до сродства похож на предложенный ув. madmasles'ом.
Упираемся в технический лимит на длину инструкций в случае, если запросов множество. Максимальный размер одной команды в SQLite - 1 Мб. Впрочем, проконтролировать создание наборов команд по 1 мб не составляет ни малейшего труда.
Но главное же тут не размер команд, а скорость выполнения скрипта.
Чисто логически можно предположить, что привязать существующие данные, которые уже подготовлены и лежат в массиве, к существующему statement'у в цикле должно занимать намного меньше времени, чем 1) извлечение строк из массива; 2) сшивание данных в одну большую строку или считывание этой строки из файла; 3) отправка набора команд через _SQLite_Exec, что обязательно сопровождается повторной компиляцией statement'а движком SQLite.
Я пытаюсь добиться максимально возможной скорости средствами AutoIt, поэтому, собственно говоря, эта тема и была создана.


Добавлено:
Сообщение автоматически объединено:

Если заглянуть в исходники SQLite.au3, функции _SQLite_Query() и _SQLite_FetchData(), там осуществляется передача данных посредством DllCall.
Адрес statement'a получаем в ходе выполнения кода:
Код:
Local $iRval = DllCall($__g_hDll_SQLite, "int:cdecl", "sqlite3_prepare16_v2", _
			"ptr", $hDB, _
			"wstr", $sSQL, _
			"int", -1, _
			"ptr*", 0, _ ; OUT: Statement handle
			"ptr*", 0) ; OUT: Pointer to unused portion of zSql
; $hQuery = $iRval[4]


А получение данных с этого statement'a - через такой вызов:
Код:
Local $iRval_Step = DllCall($__g_hDll_SQLite, "int:cdecl", "sqlite3_step", "ptr", $hQuery)

sqlite_step просто повторно выполняет statement, указанный в $hQuery, и если привязать к нему новые данные - выполнит с новыми данными.
Подтверждение данного функционала есть в стартовом сообщении.

Вот чего я понять не могу, так это как привязать данные к существующему statement'у?
Если придумаем способ привязать данные, сможем вызывать раз за разом этот же код:
Код:
Local $iRval_Step = DllCall($__g_hDll_SQLite, "int:cdecl", "sqlite3_step", "ptr", $hQuery)

и иметь офигительную скорость вставки данных. Безо всяких костылей типа DDL или сшитых мегабайтных строк запросов.
 

Medic84

Омега
Команда форума
Администратор
Сообщения
1,590
Репутация
341
[?]
и иметь офигительную скорость вставки данных. Безо всяких костылей типа DDL или сшитых мегабайтных строк запросов.

Мы и так имеем офигенную скорость вставки данных.

В твоем листинге по C++ я не увидел ничего сверхестественного, точно также считывается файл и формируется отдельный SQL запрос, после чего он сразу его выполняет, а не куда то записывает.
А скорость выполнения зависит от ключевого слова: BEGIN TRANSACTION

Код:
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &sErrMsg);

Я немного модифицировал код madmasles.

Код:
#include <SQLite.au3>

Local $s_FileDB = @ScriptDir & '\Test.db', $h_DB, $a_Data[100001][2] = [[100000]], $i_Timer, $aRes, $iRows, $iColumns

For $i = 1 To $a_Data[0][0]
    $a_Data[$i][0] = $i
    $a_Data[$i][1] = Hex($i, 8)
Next

_SQLite_Startup()
If @error Then Exit 1

$h_DB = _SQLite_Open($s_FileDB)
If @error Then Exit 2

;_SQLite_Exec($h_DB, 'BEGIN TRANSACTION;')
_SQLite_Exec($h_DB, 'DROP TABLE IF EXISTS TEST_TABLE;CREATE TABLE TEST_TABLE ([NUM_INT] INTEGER, [NUM_HEX] TEXT);')

For $i = 1 To $a_Data[0][0]
	;$i_Timer = TimerInit()
    _SQLite_Exec($h_DB, 'INSERT INTO TEST_TABLE VALUES (' & $a_Data[$i][0] & ', "' & $a_Data[$i][1] & '");')
	;ConsoleWrite('Insert time: ' & TimerDiff($i_Timer) & ' msec' & @LF)
Next

;$i_Timer = TimerInit()
;_SQLite_Exec($h_DB, 'COMMIT;')
;ConsoleWrite('Insert time: ' & TimerDiff($i_Timer) & ' msec' & @LF)

If _SQLite_GetTable2d($h_DB, 'SELECT * FROM TEST_TABLE;', $aRes, $iRows, $iColumns) Then
    ConsoleWrite('ERROR' & @LF)
Else
    ConsoleWrite('$iRows: ' & $iRows & @LF)
    ConsoleWrite('$iColumns: ' & $iColumns & @LF)
    _ArrayDisplay($aRes, 'TEST_TABLE')
EndIf

_SQLite_Close($h_DB)
_SQLite_Shutdown()


Получаем такие показатели:
Код:
Insert time: 5.56327275556449 msec
Insert time: 3.82163488657067 msec
Insert time: 5.1386016325525 msec
Insert time: 5.51869849646972 msec
Insert time: 3.42451876008999 msec
Insert time: 3.56877727134216 msec
Insert time: 3.66967718511123 msec
Insert time: 3.27863936668893 msec
Insert time: 4.10812580638887 msec
Insert time: 3.60200535539462 msec
Insert time: 5.03891738039511 msec
Insert time: 3.80461562400721 msec
Insert time: 5.06160973047972 msec
Insert time: 3.49826889786497 msec
Insert time: 4.64950044412171 msec
Insert time: 4.25967828731109 msec
Insert time: 6.14233290325927 msec
Insert time: 4.11096235014945 msec
Insert time: 6.30685244137269 msec
Insert time: 4.1198772019684 msec
Insert time: 24.4850457412942 msec
Insert time: 7.293564449516 msec
Insert time: 4.82536615727744 msec
Insert time: 4.16769322536097 msec
Insert time: 5.75413162859755 msec
Insert time: 4.76985094367759 msec
Insert time: 4.81726174653293 msec
Insert time: 4.73864896231125 msec
Insert time: 4.48862789084331 msec
Insert time: 4.93112871749321 msec
Insert time: 3.94968457633382 msec
Insert time: 4.74634815251853 msec
Insert time: 4.81442520277236 msec
Insert time: 4.13000771539903 msec
Insert time: 4.47647127472656 msec
Insert time: 6.43003948468915 msec
Insert time: 4.56643023399055 msec
Insert time: 4.171340210196 msec
Insert time: 4.8634568877766 msec
Insert time: 4.65476831110564 msec
Insert time: 5.44575879976919 msec
Insert time: 4.99353268022589 msec
Insert time: 6.84174355050993 msec
Insert time: 5.0920012707716 msec
Insert time: 27.1817884165278 msec
Insert time: 5.79303280017117 msec
Insert time: 5.27880793843241 msec
Insert time: 11.313757399327 msec
Insert time: 16.3089109617018 msec
Insert time: 6.08033416106382 msec
Insert time: 22.2903713116827 msec
Insert time: 16.2489383221925 msec
Insert time: 18.8962440918846 msec
Insert time: 11.1909755765478 msec
Insert time: 9.28400772836609 msec
Insert time: 16.1500645111095 msec
Insert time: 21.99577598112 msec
Insert time: 18.9914709181325 msec
Insert time: 28.2698055589774 msec
Insert time: 11.5175833295513 msec
Insert time: 12.9435544000467 msec
Insert time: 17.0678890279246 msec
Insert time: 35.684936169661 msec
Insert time: 19.4850295324728 msec
Insert time: 20.9786724326848 msec
Insert time: 5.08916472701103 msec
Insert time: 3.76855099619417 msec
Insert time: 5.57340326899512 msec
Insert time: 4.2292867470192 msec
Insert time: 4.47525561311488 msec
Insert time: 6.15003209346655 msec
Insert time: 3.00876248889696 msec
Insert time: 3.64698483502662 msec
Insert time: 3.67535027263238 msec
Insert time: 5.64593774515843 msec
Insert time: 4.29128548921465 msec
Insert time: 3.43464927352062 msec
Insert time: 2.83694898111348 msec
Insert time: 16.0078321025435 msec
Insert time: 3.31591965611364 msec
Insert time: 2.89124853310166 msec
Insert time: 7.34624311935528 msec
Insert time: 3.76571445243359 msec
Insert time: 4.60573662610139 msec
Insert time: 4.70501565772156 msec
Insert time: 5.60622613251036 msec
Insert time: 4.33829107153277 msec
Insert time: 4.20051608887621 msec
Insert time: 4.14054344936688 msec
Insert time: 4.43513877992959 msec
Insert time: 4.64625867982391 msec
Insert time: 4.10731536531442 msec
Insert time: 5.51221496787412 msec

Расскоментируем строки начала транкзации и завершения:
Код:
#include <SQLite.au3>

Local $s_FileDB = @ScriptDir & '\Test.db', $h_DB, $a_Data[100001][2] = [[100000]], $i_Timer, $aRes, $iRows, $iColumns

For $i = 1 To $a_Data[0][0]
    $a_Data[$i][0] = $i
    $a_Data[$i][1] = Hex($i, 8)
Next

_SQLite_Startup()
If @error Then Exit 1

$h_DB = _SQLite_Open($s_FileDB)
If @error Then Exit 2

_SQLite_Exec($h_DB, 'BEGIN TRANSACTION;')
_SQLite_Exec($h_DB, 'DROP TABLE IF EXISTS TEST_TABLE;CREATE TABLE TEST_TABLE ([NUM_INT] INTEGER, [NUM_HEX] TEXT);')

For $i = 1 To $a_Data[0][0]
	;$i_Timer = TimerInit()
    _SQLite_Exec($h_DB, 'INSERT INTO TEST_TABLE VALUES (' & $a_Data[$i][0] & ', "' & $a_Data[$i][1] & '");')
	;ConsoleWrite('Insert time: ' & TimerDiff($i_Timer) & ' msec' & @LF)
Next

;$i_Timer = TimerInit()
_SQLite_Exec($h_DB, 'COMMIT;')
;ConsoleWrite('Insert time: ' & TimerDiff($i_Timer) & ' msec' & @LF)

If _SQLite_GetTable2d($h_DB, 'SELECT * FROM TEST_TABLE;', $aRes, $iRows, $iColumns) Then
    ConsoleWrite('ERROR' & @LF)
Else
    ConsoleWrite('$iRows: ' & $iRows & @LF)
    ConsoleWrite('$iColumns: ' & $iColumns & @LF)
    _ArrayDisplay($aRes, 'TEST_TABLE')
EndIf

_SQLite_Close($h_DB)
_SQLite_Shutdown()


Получаем:
Код:
Insert time: 0.199368504314788 msec
Insert time: 0.172623948857926 msec
Insert time: 0.165735199725098 msec
Insert time: 0.166140420262324 msec
Insert time: 0.165735199725098 msec
Insert time: 0.166545640799549 msec
Insert time: 0.165329979187873 msec
Insert time: 0.164924758650648 msec
Insert time: 0.165735199725098 msec
Insert time: 0.250021071467936 msec
Insert time: 0.178297036379079 msec
Insert time: 0.166545640799549 msec
Insert time: 0.164924758650648 msec
Insert time: 0.166140420262324 msec
Insert time: 0.165735199725098 msec
Insert time: 0.166950861336774 msec
Insert time: 0.166140420262324 msec
Insert time: 0.165329979187873 msec
Insert time: 0.165735199725098 msec
Insert time: 0.165329979187873 msec
Insert time: 0.165735199725098 msec
Insert time: 0.166545640799549 msec
Insert time: 0.165329979187873 msec
Insert time: 0.165735199725098 msec
Insert time: 0.165735199725098 msec
Insert time: 0.165329979187873 msec
Insert time: 0.166545640799549 msec
Insert time: 0.165329979187873 msec
Insert time: 0.166140420262324 msec
Insert time: 0.165329979187873 msec
Insert time: 0.164924758650648 msec
Insert time: 0.165735199725098 msec
Insert time: 0.167761302411224 msec
Insert time: 0.164924758650648 msec
Insert time: 0.165329979187873 msec
Insert time: 0.165329979187873 msec
Insert time: 0.165735199725098 msec
Insert time: 0.167761302411224 msec
Insert time: 0.165329979187873 msec
Insert time: 0.165329979187873 msec
Insert time: 0.165329979187873 msec
Insert time: 0.165735199725098 msec
Insert time: 0.165329979187873 msec
Insert time: 0.265824672419718 msec
Insert time: 0.171003066709026 msec
Insert time: 0.166545640799549 msec
Insert time: 0.166950861336774 msec
Insert time: 0.166545640799549 msec
Insert time: 0.224492177622749 msec
Insert time: 0.177081374767403 msec
Insert time: 0.166950861336774 msec
Insert time: 0.300268418083858 msec
Insert time: 0.197342401628662 msec
Insert time: 0.16978740509735 msec
Insert time: 0.207878135596517 msec
Insert time: 0.170597846171801 msec
Insert time: 0.165735199725098 msec
Insert time: 0.166545640799549 msec
Insert time: 0.165735199725098 msec
Insert time: 0.166545640799549 msec
Insert time: 0.166545640799549 msec
Insert time: 0.165329979187873 msec
Insert time: 0.167761302411224 msec
Insert time: 0.282033493908725 msec
Insert time: 0.171408287246251 msec
Insert time: 0.167356081873999 msec
Insert time: 0.166545640799549 msec
Insert time: 0.1689769640229 msec
Insert time: 0.166950861336774 msec
Insert time: 0.166950861336774 msec
Insert time: 0.166140420262324 msec
Insert time: 0.166140420262324 msec
Insert time: 0.166545640799549 msec

Все из-за того, что SQLite вынужден открывать/закрывать файл базы данных при выполнении каждой транзакции, т. е. в вашем тесте в каждой итерации. Однако если выполнять все итерации в одной транзакции, то он оказывается быстрее MySQL
 

Medic84

Омега
Команда форума
Администратор
Сообщения
1,590
Репутация
341
Вставка 1 миллиона строк заняла 171 секунду на ноутбуке.
Код:
Insert time: 170910.991282896 msec
 
Автор
veretragna

veretragna

Как писал, так и работает.
Сообщения
140
Репутация
10
Medic84, я это отлично знаю.
В своем рабочем скрипте я использую приблизительно такую схему: "PRAGMA SYNCHRONOUS = off; BEGIN TRANSACTION;", раз в 1000 запросов "COMMIT;", в конце цикла "END TRANSACTION;". Можно было бы избавится от коммита ради скорости, но я решил перестраховаться - вдруг какой-то сбой и данные пропадут.
Скорость неплохая, но мы можем сделать и быстрее: кто знает, сколько данных насобирается за год работы.

Medic84 сказал(а):
точно также считывается файл и формируется отдельный SQL запрос, после чего он сразу его выполняет, а не куда то записывает.

Нет, не точно так же. Отдельный SQL запрос создается единожды (sqlite3_prepare_v2();), после чего в цикле к нему привязываются новые данные с помощью функций sqlite3_bind_text(), и этот же запрос выполняется повторно, без перекомпоновки движком SQLite, только с новыми данными.

Предлагаю не строить аргументов типа "зачем автору поста эта функция? пусть использует то, что есть!", а конструктивно подумать над прямо заданным вопросом.
Я бы не стал просить сообщество о помощи, предварительно не исследовав тему.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Medic84,
Я много экспериментировал с отправкой массива в базу данных и пришел к выводу, что самый быстрый вариант - отправлять данные одной строкой. Отправлял так максимум 1 200 000 строк в 3 колонки (данные типа [3407734784, 3407735039, 210])
 

Medic84

Омега
Команда форума
Администратор
Сообщения
1,590
Репутация
341
veretragna
Окей. Специально для тебя замарочился:
Код:
#include <SQLite.au3>

Local $s_FileDB = @ScriptDir & '\Test.db', $h_DB, $a_Data[10001][2] = [[10000]], $i_Timer, $aRes, $iRows, $iColumns
Local $hQuery = null

For $i = 1 To $a_Data[0][0]
    $a_Data[$i][0] = $i
    $a_Data[$i][1] = Hex($i, 8)
Next

_SQLite_Startup()
If @error Then Exit 1

$h_DB = _SQLite_Open($s_FileDB)
If @error Then Exit 2

_SQLite_Exec($h_DB, 'DROP TABLE IF EXISTS TEST_TABLE;CREATE TABLE TEST_TABLE ([NUM_INT] INTEGER, [NUM_HEX] TEXT);')

$i_Timer = TimerInit()
_SQLite_Exec($h_DB, 'BEGIN TRANSACTION;')

_SQLite_Query($h_DB, 'INSERT INTO TEST_TABLE VALUES (?, ?);',$hQuery) ;Компонуем шаблон запроса
For $i = 1 To $a_Data[0][0]
    _SQLite_BindText($hQuery, 1, $a_Data[$i][0]) ;Вставляем данные в скомпонованный шаблон
    _SQLite_BindText($hQuery, 2, $a_Data[$i][1]) ;Вставляем данные в скомпонованный шаблон
    _SQLite_Step($hQuery) 			;Выполняем запрос
    _SQLite_ClearBindings($hQuery) 	;Подчищаемся
    _SQLite_QueryReset($hQuery) 	;Подчищаемся
Next

_SQLite_QueryFinalize($hQuery)
_SQLite_Exec($h_DB, 'END TRANSACTION;')

ConsoleWrite('Insert time: ' & TimerDiff($i_Timer) & ' msec' & @LF)

If _SQLite_GetTable2d($h_DB, 'SELECT * FROM TEST_TABLE;', $aRes, $iRows, $iColumns) Then
    ConsoleWrite('ERROR' & @LF)
Else
    ConsoleWrite('$iRows: ' & $iRows & @LF)
    ConsoleWrite('$iColumns: ' & $iColumns & @LF)
    _ArrayDisplay($aRes, 'TEST_TABLE')
EndIf

_SQLite_Close($h_DB)
_SQLite_Shutdown()

Func _SQLite_BindText($hQuery, $iRowID, $sTextRow)
    Local $iRval = DllCall($__g_hDll_SQLite, "int:cdecl", "sqlite3_bind_text16", _
            "ptr", $hQuery, _
            "int", $iRowID, _
            "wstr", $sTextRow, _
            "int", -1, _
            "ptr", NULL)
    If @error Then Return SetError(1, @error, $SQLITE_MISUSE) ; DllCall error
    If $iRval[0] <> $SQLITE_OK Then
        Return SetError(-1, 0, $iRval[0])
    EndIf
    Return $iRval[0]
EndFunc

Func _SQLite_ClearBindings($hQuery)
    Local $avRval = DllCall($__g_hDll_SQLite, "int:cdecl", "sqlite3_clear_bindings", "ptr", $hQuery)

    If @error Then Return SetError(1, @error, $SQLITE_MISUSE) ; DllCall error
    If $avRval[0] <> $SQLITE_OK Then SetError(-1)
    Return $avRval[0]
EndFunc

Func _SQLite_Step($hQuery)
    Local $iRval_Step = DllCall($__g_hDll_SQLite, "int:cdecl", "sqlite3_step", "ptr", $hQuery)
    If @error Then Return SetError(1, @error, $SQLITE_MISUSE) ; DllCall error
	Return $iRval_Step[0]
EndFunc


Вид сырой, но работает. Думаю дальше сам разберешься.

Update:
Ладно, признаю, этот способ оказался на 26 секунд быстрее.

Код:
Insert time: 144821.683918256 msec
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
veretragna собрались изучать C++, а биндинг параметров не осилили? В коде видно же какие функции используются, sqlite3_bind_text, sqlite3_prepare_v2, sqlite3_clear_bindings, sqlite3_reset если в стандартной UDF они не разу ни используются, это не значит что их в принципе нельзя использовать, всего то, написать свои функции. Вот и документация имеется http://www.sqlite.org/c3ref/bind_blob.html.
А то что в столе заказов это не делают за вас - всего лишь говорит, что это никому не надо. Все привыкли "пихать одной многомегабайтной строкой" :D вот и вас наставляют на этот грешный путь. Правильно, не слушайте, это все дурные советы. Вы очень правильную тему открыли, не закрывайте.
Если будете делать свою функцию, назовите ее batchInsert()
 

Medic84

Омега
Команда форума
Администратор
Сообщения
1,590
Репутация
341
inververs
Вообще, все доп функции можно было написать опираясь на документацию и SQLite.au3.

sqlite3_reset там присутствует, и называется:
Код:
_SQLite_QueryReset()
 
Верх