System.Data.SQLite медленное выполнение большого скрипта

Я пытаюсь запустить файл SQL из своего .NET-приложения, но время выполнения очень медленное. Я не уверен, как его оптимизировать, чтобы он работал быстрее. Я знаю, что сценарий работает, потому что, когда я запускаю его в приложении оболочки SQLite, он выполняется менее чем за 1 секунду. В моем .NET-приложении он просто зависает на sqlite_cmd.ExecuteNonQuery().

Вот отрывок из файла script.sql:

--
-- File generated with SQLiteStudio v3.1.1 on Thu Feb 15 11:33:12 2018
--
-- Text encoding used: System
--
PRAGMA foreign_keys = off;
BEGIN TRANSACTION;

-- Table: Document_Type
CREATE TABLE [Document_Type] (
    [Id]    integer PRIMARY KEY AUTOINCREMENT NOT NULL,
    [Type]  nvarchar(50) NOT NULL COLLATE NOCASE

);
INSERT INTO Document_Type (Id, Type) VALUES (1, '.docx');
INSERT INTO Document_Type (Id, Type) VALUES (2, '.xlsm');
INSERT INTO Document_Type (Id, Type) VALUES (3, '.jpeg');

-- Table: Learn_More
CREATE TABLE [Learn_More] (
    [item_ID]   integer PRIMARY KEY AUTOINCREMENT NOT NULL,
    [field_name]    nvarchar(100) COLLATE NOCASE,
    [description]   text(1073741823) COLLATE NOCASE,
    [location]  char(10) COLLATE NOCASE

);
INSERT INTO Learn_More (item_ID, field_name, description, location) VALUES (1, 'System Name', 'Full descriptive name of the system.*      Example: Agency Billing System ', 'SSP1      ');
.
.
.
.
.
COMMIT TRANSACTION;
PRAGMA foreign_keys = on;

Файл script.sql состоит из 35 831 строки. Я планирую очистить типы столбцов после того, как смогу запустить его в .NET.

Мой код .NET:

Dim baseDir As String = Application.UserAppDataPath()
Dim db3Path As String = baseDir + "\Schema Scripts\ProgrammaticallyGenerateDatabase\Test.db3"
Dim sqlPath As String = baseDir + "\Schema Scripts\script.sql"

SQLiteConnection.CreateFile(db3Path)

Dim sqlite_conn = New SQLiteConnection("Data Source= " & db3Path)
Using sqlite_conn
    sqlite_conn.Open()
    Dim sqlite_cmd = sqlite_conn.CreateCommand()
    'Dim sqlite_tran = sqlite_conn.BeginTransaction()

    'Using sqlite_tran

        Using sqlite_cmd
            Try
                sqlite_cmd.CommandText = File.ReadAllText(sqlPath)
                sqlite_cmd.ExecuteNonQuery()

                sqlite_cmd.CommandText = "SELECT Type FROM Document_Type"

                Dim sqlite_datareader = sqlite_cmd.ExecuteReader()
                While (sqlite_datareader.Read())
                    Dim textReader As String = sqlite_datareader.GetString(0)

                    Console.WriteLine(textReader)
                End While
            Catch ex As Exception
                'End Using
                'sqlite_tran.Commit()
            End Try
        End Using
    sqlite_conn.Close()
End Using

Я пробовал использовать File.OpenText(sqlPath).ReadToEnd(), но возникла та же проблема с производительностью.

Есть идеи, как это ускорить? Повторюсь, тот же файл запускается менее чем за 1 секунду в программе оболочки SQLite с использованием команды .read script.sql.

РЕДАКТИРОВАТЬ:

Это беспроигрышное приложение. Код выполняется в фоновом потоке и занимает 483801 миллисекунду.

Я придумал решение, которое работает в моем случае. Теперь запрос выполняется через ~ 700-900 мсек. Я просто связываю sqlite3.exe со своим приложением и вызываю его из командной строки.

Вот код:

Private Sub SQLiteButtonPress()
        Dim baseDir As String = Application.UserAppDataPath() + "\Schema Scripts"
        Dim db3Path As String = baseDir + "\ProgrammaticallyGenerateDatabase\Test.db3"
        Dim sqlPath As String = baseDir + "\Baseline Schema.sql"

        Dim watch = System.Diagnostics.Stopwatch.StartNew()
        Console.WriteLine("Starting Stopwatch")

        Try
            Dim proc As New System.Diagnostics.ProcessStartInfo()
            proc.Arguments = "/c sqlite3.exe """ + db3Path + """ < """ + sqlPath + """"
            proc.FileName = "cmd.exe"
            proc.UseShellExecute = False
            proc.CreateNoWindow = True

            Dim p As New Process()
            p.StartInfo = proc
            p.Start()
            p.WaitForExit()

            Dim sqlite_conn = New SQLiteConnection("Data Source= " & db3Path)
            Using sqlite_conn
                sqlite_conn.Open()
                Dim sqlite_cmd = sqlite_conn.CreateCommand()

                Using sqlite_cmd
                        sqlite_cmd.CommandText = "SELECT Type FROM Document_Type"

                        Dim sqlite_datareader = sqlite_cmd.ExecuteReader()
                        While (sqlite_datareader.Read())
                            Dim textReader As String = sqlite_datareader.GetString(0)

                            Console.WriteLine(textReader)
                        End While
                End Using
                sqlite_conn.Close()
            End Using

        Catch ex As Exception
            Throw ex
        End Try

        watch.Stop()
        Dim elapsedMs = watch.ElapsedMilliseconds
        Console.WriteLine("Finished Stopwatch: " & elapsedMs & "ms")
    End Sub

person Dillon Connolly    schedule 15.02.2018    source источник
comment
Зависает или просто долго (сколько) доделывается?   -  person Mark Benningfield    schedule 16.02.2018
comment
Вы уверены, что это проблема File.ReadAllText? Я бы попробовал сделать этот код асинхронным. Также в какой среде вы его запускаете? (Это мобильное приложение, приложение для выигрыша, приложение для сервера?)   -  person Nick Polyderopoulos    schedule 16.02.2018
comment
@MarkBenningfield Запуск занимает 483801 миллисекунду.   -  person Dillon Connolly    schedule 16.02.2018
comment
@NickPolideropoulos Я последовал твоему совету и переместил этот код в фоновый рабочий. Выполнение по-прежнему занимает ненормально много времени. Это в выигрышном приложении. Мне нужно иметь возможность сгенерировать базу данных с помощью кода на пользовательских машинах, чтобы позже я мог предоставлять ей обновления, не стирая их пользовательские данные.   -  person Dillon Connolly    schedule 16.02.2018
comment
@DillonConnolly После небольшого исследования я нашел эти две ссылки. файл с отображением памяти и блог с различными методами загрузки файлов Быстрый способ чтения текстовых файлов. Не могли бы вы попробовать его раскрутить? Также не могли бы вы измерить время, необходимое для загрузки файла, и время, необходимое для выполнения команды? Возможно, будет быстрее запускать их по частям.   -  person Nick Polyderopoulos    schedule 16.02.2018
comment
Попробуйте разделить строку SQL на точку с запятой и ввести каждый оператор в текст команды в цикле. Просто догадка.   -  person Mark Benningfield    schedule 16.02.2018


Ответы (2)


У меня такая же проблема. Совет от @MarkBenningfield решил проблему. Как он уже упоминал, разделите ваш скрипт на точку с запятой и запустите каждый оператор отдельно в цикле. После этого у меня все пошло очень быстро.

person Darkhan Zholmukhanov    schedule 18.01.2019

По какой-то причине библиотека .NET SQLite не выполняет большие запросы в одной строке очень быстро, даже если вы оборачиваете каждую массовую вставку в транзакцию; или оберните весь вызов метода ExeecuteNonQuery внутри транзакции.

Вышеупомянутое решение работает: разделите ваш большой файл SQL на отдельные операторы, выполните все из них в транзакции, а затем выполните фиксацию. Таким образом я смог загрузить 15 000 записей в экземпляр SQLite на основе памяти за 0,22 секунды.

Ваше здоровье.

person Matt Drouillard    schedule 21.03.2019