none
Долго идет запись в базу данных SQLLite

    Вопрос

  • Вот так пишу в базу. На проблема в том, что запись идет очень долго. При этом в плагине файер фокса запись идет моментально. Почему?

      private void button_Click(object sender, RoutedEventArgs e)
            {
                 Thread myThread = new Thread(new ParameterizedThreadStart(InsertInBase));
                  myThread.Start(sqlLite);
            }
            private static void InsertInBase(object sqlLite)
            {
               
                foreach (Trade trade in MainWindow.Instance.Trader.Trades)
             
                      ((SqlLite)sqlLite).InsertTrade(trade);
               
                
             
            }

       public void InsertTrade(Trade trade)
            {

                 cmd = con.CreateCommand();
                 cmd.CommandText = " SELECT qty from " + TradesTable + " where transId='" + trade.Id.ToString() + "'";
                 IDataReader reader = cmd.ExecuteReader();
                 int count = 0;

                 while (reader.Read())
                 {

                     count = count + 1;
                 }
                 if (count != 0) return;
                 

                string idSec =  GetSecId(trade.Security).ToString();
                    string dir = "-1";
                    if (trade.OrderDirection == StockSharp.Messages.Sides.Buy)
                        dir = "0";
                    if (trade.OrderDirection == StockSharp.Messages.Sides.Sell)
                        dir = "1";
                if (counter < range)
                {
                    this.transaction = this.transaction+"INSERT INTO " + TradesTable + "(sec,dir,qty,transId,time) VALUES ('" + idSec + "','" + dir + "','" + trade.Volume.ToString() + "','" + trade.Id.ToString() + "','" + trade.Time.Ticks + "');";
                }
                if (counter >=range&&!writeInFile)
                {
                    //writeInFile = true;
                    this.transaction = "BEGIN TRANSACTION;"+ this.transaction +"COMMIT;";
                   cmd.CommandText = this.transaction;
                    cmd.ExecuteNonQuery();
                    counter = 0;
                  //  System.IO.File.WriteAllText("WriteText.txt", this.transaction);
                    this.transaction = "";
                   
                }
              
                counter++;

            }


    • Изменено qpiles 20 апреля 2017 г. 15:13
    20 апреля 2017 г. 15:08

Ответы

  • А сколько у вас записей? Сколько времени занимает добавление одной записи?

    В любом случае вот что можно попробовать:

    1. Вместо создания одной длиной текстовой команды следует начать транзакцию, зачем выполнить команды, затем завершить транзакцию.

    2. Следует использовать одну подготовленную команду лишь меняя параметры. Использование параметров в общем обязательно и по многим другим причинам.



    This posting is provided "AS IS" with no warranties, and confers no rights.

    • Предложено в качестве ответа Taras KovalenkoEditor 21 апреля 2017 г. 13:29
    • Помечено в качестве ответа Taras KovalenkoEditor 22 апреля 2017 г. 11:18
    21 апреля 2017 г. 7:12

Все ответы

  • Если я правильно понял этот "код", то в цикле сперва происходит чтение из БД, потом открывается транзакция и делается вставка в БД.

    Нужно сперва открыть транзакцию, а потом, внутри неё, делать в цикле все инсёрты. Причём без селектов.

    20 апреля 2017 г. 16:45
  • Добрый день.

    1. Вы считываете все записи с совпадающим transId, только для того, чтобы посчитать их количество. замените свой select на вызов функции Count . Будет работать быстрее.

    SELECT count(qty) from ...

    2. Попробуйте воспользоваться Bulk Insert, он при большом количестве вставок работает быстрее.

    21 апреля 2017 г. 5:51
    Отвечающий
  • Сделал так. Все равно запрос из файла WriteFile идет моментально, а в С# очень долго :(


       private void button_Click(object sender, RoutedEventArgs e)
            {
                 Thread myThread = new Thread(new ParameterizedThreadStart(InsertInBase));
                  myThread.Start(sqlLite);
            }
            private static void InsertInBase(object sqlLite)
            {

                foreach (Trade trade in MainWindow.Instance.Trader.Trades)
                      ((SqlLite)sqlLite).InsertTrade(trade);

            }

     public void InsertTrade(Trade trade)
            {

                       string idSec = "1";
                    string dir = "-1";
                  range=2000;
                if (counter < range)
                {
                    this.transaction = this.transaction+"INSERT INTO " + TradesTable + "(sec,dir,qty,transId,time) VALUES ('" + idSec + "','" + dir + "','" + trade.Volume.ToString() + "','" + trade.Id.ToString() + "','" + trade.Time.Ticks + "');";
                }
                if (counter >=range&&!writeInFile)
                {
                    //writeInFile = true;

                    this.transaction = "BEGIN TRANSACTION;"+ this.transaction +"COMMIT;";
                    cmd = con.CreateCommand();
                   cmd.CommandText = this.transaction;
                    cmd.ExecuteNonQuery();
                    counter = 0;
                    System.IO.File.WriteAllText("WriteText.txt", this.transaction);
                    this.transaction = "";
                   
                }
              
                counter++;

            }

    21 апреля 2017 г. 6:11
  • Добрый день.

    1. Вы считываете все записи с совпадающим transId, только для того, чтобы посчитать их количество. замените свой select на вызов функции Count . Будет работать быстрее.

    SELECT count(qty) from ...

    2. Попробуйте воспользоваться Bulk Insert, он при большом количестве вставок работает быстрее.

    1. Даже без селекта. Запись идет долго. Несколько десятков секунд
    21 апреля 2017 г. 6:12
  • А сколько у вас записей? Сколько времени занимает добавление одной записи?

    В любом случае вот что можно попробовать:

    1. Вместо создания одной длиной текстовой команды следует начать транзакцию, зачем выполнить команды, затем завершить транзакцию.

    2. Следует использовать одну подготовленную команду лишь меняя параметры. Использование параметров в общем обязательно и по многим другим причинам.



    This posting is provided "AS IS" with no warranties, and confers no rights.

    • Предложено в качестве ответа Taras KovalenkoEditor 21 апреля 2017 г. 13:29
    • Помечено в качестве ответа Taras KovalenkoEditor 22 апреля 2017 г. 11:18
    21 апреля 2017 г. 7:12
  • Да даже просто 2000 записей записываешь( это одна порция) в С# десятки секунд. В плагине файера - моментально

    А можно пример какой-нибудь как пишется у Вас?

    21 апреля 2017 г. 7:46
  • Я уже пробовал прописывать построчно. Получается одно и тоже
    21 апреля 2017 г. 7:57
  • Если идет медленно вставка именно из C# клиента, посмотрите строку подключения, может в ней чего забыли указать типа пулинга или параллельного выполнения. C SQLite не работал, точно не подскажу. Ну и посмотрите в сторону BULK INSERT они будут быстрее.
    21 апреля 2017 г. 8:11
    Отвечающий
  • Если идет медленно вставка именно из C# клиента, посмотрите строку подключения, может в ней чего забыли указать типа пулинга или параллельного выполнения. C SQLite не работал, точно не подскажу. Ну и посмотрите в сторону BULK INSERT они будут быстрее.

    Вот как создаю подключение

    con = new SqliteConnection();
                this.dbFilename = dbFilename;
                string cs = string.Format("Version=3,uri=file:{0}", dbFilename);
                con.ConnectionString = cs;
                con.Open();
                cmd = con.CreateCommand();

                
                cmd.CommandText = "CREATE TABLE IF NOT EXISTS " + SecTable + " (id INTEGER PRIMARY KEY AUTOINCREMENT,sec TEXT NOT NULL)";
                cmd.ExecuteNonQuery();
                cmd.CommandText = "CREATE TABLE IF NOT EXISTS " + TradesTable + " (sec TEXT NOT NULL,dir INTEGER NOT NULL,qty INTEGER NOT NULL,transId INTEGER NOT NULL,time REAL NOT NULL)";
                cmd.ExecuteNonQuery();
                cmd.CommandText = "PRAGMA synchronous = NORMAL";
                cmd.ExecuteNonQuery();
             

    21 апреля 2017 г. 10:53
  •  this.transaction = System.IO.File.ReadAllText("WriteText.txt");

                    cmd = con.CreateCommand();
                    cmd.CommandText = this.transaction;
                    cmd.ExecuteNonQuery();

    Считываю файл, в котором 2000 строк . пишет 27 секунд

    BEGIN TRANSACTION;INSERT INTO trades(sec,dir,qty,transId,time) VALUES ('1','1','1','7991410','636283008012900000');INSERT INTO trades(sec,dir,qty,transId,time) VALUES ('1','1','1','7991412','636283008013620000');INSERT INTO trades(sec,dir,qty,transId,time) VALUES ('1','1','1','7991413','636283008013620000');INSERT INTO trades(sec,dir,qty,transId,time) VALUES ('1','1','1','7991414','636283008013620000');INSERT INTO trades(sec,dir,qty,transId,time) VALUES ('1','0','1','7991415','636283008013880000');INSERT INTO trades(sec,dir,qty,transId,time) VALUES ('1','0','2','7991416','636283008013880000');INSERT INTO trades(sec,dir,qty,transId,time) VALUES ('1','0','2','7991417','636283008013880000');INSERT INTO trades(sec,dir,qty,transId,time) VALUES ('1','1','2','7991418','636283008013970000');INSERT INTO trades(sec,dir,qty,transId,time) VALUES 

              
    21 апреля 2017 г. 11:16
  • Добавил новую версию библиотеки через NUGET по запросу SQLITE

    Вот таким простым классом добавляю 2000 строк из файла. Все равно 6 секунд....

     public class SqlLite2
        {
            private string SecTable = "securities";
            private string TradesTable = "trades";
            string baseName = "trades.db3";


            public SqlLite2()
            {
                //private System.Data.SQLite.SqliteConnection con;
            SQLiteConnection.CreateFile(baseName);
                SQLiteFactory factory = (SQLiteFactory)DbProviderFactories.GetFactory("System.Data.SQLite");
                using (SQLiteConnection connection = (SQLiteConnection)factory.CreateConnection())
                {
                    connection.ConnectionString = "Data Source = " + baseName;
                    connection.Open();

                    using (SQLiteCommand command = new SQLiteCommand(connection))
                    {
                        command.CommandText = @"CREATE TABLE  IF NOT EXISTS [trades] (
                        [sec] TEXT NOT NULL,
                        [dir] INTEGER NOT NULL,
                        [qty] INTEGER NOT NULL,
                        [transId] INTEGER NOT NULL,
                        [time] REAL NOT NULL
                        );";
                        command.CommandType = CommandType.Text;
                        command.ExecuteNonQuery();
                    }
                   
                }
                
              
            }
            public void LoadTrade()
            {


              string transaction = System.IO.File.ReadAllText("WriteText.txt");
                SQLiteFactory factory = (SQLiteFactory)DbProviderFactories.GetFactory("System.Data.SQLite");
                using (SQLiteConnection connection = (SQLiteConnection)factory.CreateConnection())
                {
                    connection.ConnectionString = "Data Source = " + baseName;
                    connection.Open();

                    using (SQLiteCommand command = new SQLiteCommand(connection))
                    {
                        command.CommandText = transaction;
                        command.CommandType = CommandType.Text;
                        command.ExecuteNonQuery();
                    }
                   
                }

              
           }
           }
       }

    21 апреля 2017 г. 13:21
  • Уверены что в "плагине" вы правильно измеряйте время, например не время асинхронного вызова? Данные по факту добавились? 

    Судя по старой статье (ниже) скорость добавления может очень сильно меняться, но в общем достижимы десятки тысяч записей в секунду (а на новом оборудовании наверное и сотни тысяч):

    http://stackoverflow.com/questions/1711631/improve-insert-per-second-performance-of-sqlite


    This posting is provided "AS IS" with no warranties, and confers no rights.

    21 апреля 2017 г. 16:07
  • Про какое время идет речь?

    В последнем примере просто нет никакого времени.

    Десятки тысяч  в секунду- я был рад как макака. Но покамест только 2000 за 7 секунд

    21 апреля 2017 г. 17:40
  • Блин по ссылку там C++ :(
    21 апреля 2017 г. 17:47
  • Сделал 

    PRAGMA synchronous = OFF

    и

    PRAGMA journal_mode = MEMORY

    Итого 4 секунды. Уже лучше!

    21 апреля 2017 г. 18:25
  • Блин по ссылку там C++ :(

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

    Скажем, используйте один подготовленный запрос с параметерами вместо слияния тысяч запросов в одну огромную строку. Это однозначно самый медленный вариант.


    This posting is provided "AS IS" with no warranties, and confers no rights.

    21 апреля 2017 г. 19:51