Как увеличить скорость массивного INSERT в ADO.NET?

Я скачал пробную версию Advanced Database Server (ADS) 10.1 вместе с поставщиком ARC и ADO.NET. Моя главная цель состояла в том, чтобы узнать производительность массивных INSERTS из миллионов записей по сравнению с SQLite .NET (http://sqlite.phxsoftware.com/).

В ADS за 30 минут было загружено 7 миллионов записей.

В Sqlite для .NET те же 7 миллионов записей были загружены менее чем за 3 минуты!

Почему? Что я могу сделать, чтобы повысить скорость в ADS с поставщиком .NET?

С Уважением .

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

Спасибо за ваши рекомендации, В коде ADS я по ошибке включил создание некоторых индексов, когда я это подавил, время загрузки истекло 10 минут.

Позвольте мне добавить пример кода и примеры данных (которые вы можете умножить, пока не получите 7 миллионов записей). Если вы можете найти способы улучшить и оптимизировать производительность, сообщите мне об этом.

КОД ДЛЯ ОБЪЯВЛЕНИЙ SYBASE:

 public void LoadAds(string opt, string file)
    {
        AdsConnection conn = new AdsConnection(@"data source=C:\apps\dataApps\cmpExistenc\inv.ads;" +
            "ServerType=local; TableType=ADT");
        conn.Open();
        var stV = new st();
        var dicTxt = new Dictionary<object, st>();
        if (opt.ToUpper() == "C")
        {
            using (AdsCommand cmd = conn.CreateCommand())
            {
                try
                {
                    cmd.CommandText = "DROP TABLE lbl; DROP TABLE almlbl";
                    cmd.ExecuteNonQuery();
                }
                catch { }
                cmd.CommandText =
                    "CREATE TABLE lbl (alm varchar(4), alm2 varchar(4), " +
                       "mat varchar(18), ser varchar(20), fac varchar(18), almlbl varchar(10), " +
                       "cant integer, sts varchar(1), ser
public void LoadSQLITE(string opt, string file)
    {
        conn = new SQLiteConnection
            (@"Data Source=inv.db3; Page Size=65536; Cache Size=65536; Synchronous=Off; Journal Mode=Off;");
        conn.Open();
        var stV = new st();
        var dicTxt = new Dictionary<object, st>(); // faster than SortedDictionary
        if (opt.ToUpper() == "C")
        {
            using (SQLiteCommand cmd = new SQLiteCommand(conn))
            {
                try
                {
                    cmd.CommandText = "DROP TABLE lbl; DROP TABLE almlbl";
                    cmd.ExecuteNonQuery();
                }
                catch { }
                cmd.CommandText =
                    "CREATE TABLE lbl (alm varchar(4), alm2 varchar(4), " +
                       "mat varchar(18), ser varchar(20), fac varchar(18), almlbl varchar(10), " +
                       "cant integer, sts varchar(1), ser_2_20 varchar(20), rowid_sap integer, stsmat varchar);" +
                    "CREATE TABLE almlbl (almlbl varchar(10), almlbltxt varchar(100), " +
                       "ciudad varchar(50));"; //+
                cmd.ExecuteNonQuery();
            }
        }
        else
            using (SQLiteCommand cmdTxt = new SQLiteCommand(conn))
            {
                cmdTxt.CommandText = "SELECT * from almlbl";
                SQLiteDataReader drT = cmdTxt.ExecuteReader();
                while (drT.Read())
                    dicTxt[drT[0]] = new st() { almlblTxt = drT[1], ciudad = drT[2] };
                drT.Dispose();
                cmdTxt.CommandText = "DELETE FROM almlbl";
                cmdTxt.ExecuteNonQuery();
            }

        using (SQLiteTransaction transac = conn.BeginTransaction())
        {
            using (SQLiteCommand cmd = new SQLiteCommand(conn))
            {
                SQLiteParameter param = new SQLiteParameter();
                SQLiteCommand cmdAux = LibCorp.Lite.buildParmsFromTable("lbl", conn);
                cmd.CommandText = cmdAux.CommandText;
                foreach (SQLiteParameter sp in cmdAux.Parameters)
                    cmd.Parameters.Add(sp);
                long regLei = 0;
                try
                {
                    StreamReader sr = new StreamReader(file, Encoding.Default);
                    sr.ReadLine(); // Ignore title
                    List<object> cols;
                    string line;
                    while (!string.Equals(line = sr.ReadLine(), null)) // Fastest way
                    {
                        if ((++regLei % 1000000) == 0)  //Diff of only 1 or 2 secs if omitted
                            o.show(string.Format(" lbl:{0}", regLei), tbx);
                        cols = new List<object>(line.Split('|')); // Fastest way
                        if (!dicTxt.ContainsKey((string)cols[5])) // diff of only 1 sec if commented
                        {
                            stV.almlblTxt = cols[6];
                            stV.ciudad = cols[8];
                            dicTxt[cols[5]] = stV;
                        }

                        if (!cols[3].Equals("") && cols[3].ToString().Length > 18)
                            cols.Add(cols[3].ToString().Substring(1));
                        else
                            cols.Add(DBNull.Value);

                        cmd.Parameters[0].Value = cols[0];       // alm
                        cmd.Parameters[1].Value = cols[1];       // alm2
                        cmd.Parameters[2].Value = cols[2];       // mat
                        cmd.Parameters[3].Value = cols[3];       // ser
                        cmd.Parameters[4].Value = cols[4];       // fac
                        cmd.Parameters[5].Value = cols[5];       // almlbl
                        cmd.Parameters[6].Value = cols[7];       // cant
                        cmd.Parameters[7].Value = DBNull.Value;  // sts
                        cmd.Parameters[8].Value = cols[10];      // ser_2_20
                        cmd.Parameters[9].Value = DBNull.Value;  // rowid_sap
                        cmd.Parameters[10].Value = cols[9];      // stsmat
                        cmd.ExecuteNonQuery();
                    }

                    foreach (KeyValuePair<object, st> pair in dicTxt)
                    {
                        cmd.CommandText = string.Format("INSERT INTO almlbl VALUES('{0}','{1}','{2}')",
                                pair.Key, pair.Value.almlblTxt, pair.Value.ciudad);
                        cmd.ExecuteNonQuery();
                    }

                    transac.Commit();
                }
                catch (Exception ex)
                {
                    o.notify(string.Format("{0}\n\rSitio->{1}", ex, ex.TargetSite.Name));
                }
                finally
                {
                    conn.Close();
                }
            }

        }
    }
20 varchar(20), rowid_sap integer, stsmat varchar(100));"; cmd.ExecuteNonQuery(); cmd.CommandText = "CREATE TABLE almlbl (almlbl varchar(10), almlbltxt varchar(100), " + "ciudad varchar(50));"; cmd.ExecuteNonQuery(); } } else using (AdsCommand cmdTxt = conn.CreateCommand()) { cmdTxt.CommandText = "SELECT * from almlbl"; AdsDataReader drT = cmdTxt.ExecuteReader(); while (drT.Read()) dicTxt[drT[0]] = new st() { almlblTxt = drT[1], ciudad = drT[2] }; drT.Dispose(); cmdTxt.CommandText = "DELETE FROM almlbl"; cmdTxt.ExecuteNonQuery(); } using (AdsTransaction transac = conn.BeginTransaction()) { AdsCommand cmd = conn.CreateCommand(); cmd.Transaction = transac; AdsParameter param = cmd.CreateParameter(); cmd = LibCorp.Ads.buildParmsFromTable("lbl", conn, transac); long regLei = 0; List<object> cols; try { StreamReader sr = new StreamReader(file, Encoding.Default); sr.ReadLine(); // Ignore title string line; while ((line = sr.ReadLine()) != null) { if ((++regLei % 1000000) == 0) o.show(string.Format(" lbl:{0}", regLei), tbx); cols = new List<object>(line.Split('|')); if (!dicTxt.ContainsKey((string)cols[5])) { stV.almlblTxt = cols[6]; stV.ciudad = cols[8]; dicTxt[cols[5]] = stV; } if (!cols[3].Equals("") && cols[3].ToString().Length > 18) cols.Add(cols[3].ToString().Substring(1)); else cols.Add(DBNull.Value); cmd.Parameters[0].Value = cols[0]; // alm cmd.Parameters[1].Value = cols[1]; // alm2 cmd.Parameters[2].Value = cols[2]; // mat cmd.Parameters[3].Value = cols[3]; // ser cmd.Parameters[4].Value = cols[4]; // fac cmd.Parameters[5].Value = cols[5]; // almlbl cmd.Parameters[6].Value = cols[7]; // cant cmd.Parameters[7].Value = DBNull.Value; // sts cmd.Parameters[8].Value = cols[10]; // ser
public void LoadSQLITE(string opt, string file)
    {
        conn = new SQLiteConnection
            (@"Data Source=inv.db3; Page Size=65536; Cache Size=65536; Synchronous=Off; Journal Mode=Off;");
        conn.Open();
        var stV = new st();
        var dicTxt = new Dictionary<object, st>(); // faster than SortedDictionary
        if (opt.ToUpper() == "C")
        {
            using (SQLiteCommand cmd = new SQLiteCommand(conn))
            {
                try
                {
                    cmd.CommandText = "DROP TABLE lbl; DROP TABLE almlbl";
                    cmd.ExecuteNonQuery();
                }
                catch { }
                cmd.CommandText =
                    "CREATE TABLE lbl (alm varchar(4), alm2 varchar(4), " +
                       "mat varchar(18), ser varchar(20), fac varchar(18), almlbl varchar(10), " +
                       "cant integer, sts varchar(1), ser_2_20 varchar(20), rowid_sap integer, stsmat varchar);" +
                    "CREATE TABLE almlbl (almlbl varchar(10), almlbltxt varchar(100), " +
                       "ciudad varchar(50));"; //+
                cmd.ExecuteNonQuery();
            }
        }
        else
            using (SQLiteCommand cmdTxt = new SQLiteCommand(conn))
            {
                cmdTxt.CommandText = "SELECT * from almlbl";
                SQLiteDataReader drT = cmdTxt.ExecuteReader();
                while (drT.Read())
                    dicTxt[drT[0]] = new st() { almlblTxt = drT[1], ciudad = drT[2] };
                drT.Dispose();
                cmdTxt.CommandText = "DELETE FROM almlbl";
                cmdTxt.ExecuteNonQuery();
            }

        using (SQLiteTransaction transac = conn.BeginTransaction())
        {
            using (SQLiteCommand cmd = new SQLiteCommand(conn))
            {
                SQLiteParameter param = new SQLiteParameter();
                SQLiteCommand cmdAux = LibCorp.Lite.buildParmsFromTable("lbl", conn);
                cmd.CommandText = cmdAux.CommandText;
                foreach (SQLiteParameter sp in cmdAux.Parameters)
                    cmd.Parameters.Add(sp);
                long regLei = 0;
                try
                {
                    StreamReader sr = new StreamReader(file, Encoding.Default);
                    sr.ReadLine(); // Ignore title
                    List<object> cols;
                    string line;
                    while (!string.Equals(line = sr.ReadLine(), null)) // Fastest way
                    {
                        if ((++regLei % 1000000) == 0)  //Diff of only 1 or 2 secs if omitted
                            o.show(string.Format(" lbl:{0}", regLei), tbx);
                        cols = new List<object>(line.Split('|')); // Fastest way
                        if (!dicTxt.ContainsKey((string)cols[5])) // diff of only 1 sec if commented
                        {
                            stV.almlblTxt = cols[6];
                            stV.ciudad = cols[8];
                            dicTxt[cols[5]] = stV;
                        }

                        if (!cols[3].Equals("") && cols[3].ToString().Length > 18)
                            cols.Add(cols[3].ToString().Substring(1));
                        else
                            cols.Add(DBNull.Value);

                        cmd.Parameters[0].Value = cols[0];       // alm
                        cmd.Parameters[1].Value = cols[1];       // alm2
                        cmd.Parameters[2].Value = cols[2];       // mat
                        cmd.Parameters[3].Value = cols[3];       // ser
                        cmd.Parameters[4].Value = cols[4];       // fac
                        cmd.Parameters[5].Value = cols[5];       // almlbl
                        cmd.Parameters[6].Value = cols[7];       // cant
                        cmd.Parameters[7].Value = DBNull.Value;  // sts
                        cmd.Parameters[8].Value = cols[10];      // ser_2_20
                        cmd.Parameters[9].Value = DBNull.Value;  // rowid_sap
                        cmd.Parameters[10].Value = cols[9];      // stsmat
                        cmd.ExecuteNonQuery();
                    }

                    foreach (KeyValuePair<object, st> pair in dicTxt)
                    {
                        cmd.CommandText = string.Format("INSERT INTO almlbl VALUES('{0}','{1}','{2}')",
                                pair.Key, pair.Value.almlblTxt, pair.Value.ciudad);
                        cmd.ExecuteNonQuery();
                    }

                    transac.Commit();
                }
                catch (Exception ex)
                {
                    o.notify(string.Format("{0}\n\rSitio->{1}", ex, ex.TargetSite.Name));
                }
                finally
                {
                    conn.Close();
                }
            }

        }
    }
20 cmd.Parameters[9].Value = DBNull.Value; // rowid_sap cmd.Parameters[10].Value = cols[9]; // stsmat cmd.ExecuteNonQuery(); } foreach (KeyValuePair<object, st> pair in dicTxt) { cmd.CommandText = string.Format("INSERT INTO almlbl VALUES('{0}','{1}','{2}')", pair.Key, pair.Value.almlblTxt, pair.Value.ciudad); cmd.ExecuteNonQuery(); } transac.Commit(); } catch (Exception ex) { o.notify(string.Format("{0}\n\rSitio->{1}", ex, ex.TargetSite.Name)); } finally { conn.Close(); } } }

КОД ДЛЯ SQLITE ДЛЯ .NET:

public void LoadSQLITE(string opt, string file)
    {
        conn = new SQLiteConnection
            (@"Data Source=inv.db3; Page Size=65536; Cache Size=65536; Synchronous=Off; Journal Mode=Off;");
        conn.Open();
        var stV = new st();
        var dicTxt = new Dictionary<object, st>(); // faster than SortedDictionary
        if (opt.ToUpper() == "C")
        {
            using (SQLiteCommand cmd = new SQLiteCommand(conn))
            {
                try
                {
                    cmd.CommandText = "DROP TABLE lbl; DROP TABLE almlbl";
                    cmd.ExecuteNonQuery();
                }
                catch { }
                cmd.CommandText =
                    "CREATE TABLE lbl (alm varchar(4), alm2 varchar(4), " +
                       "mat varchar(18), ser varchar(20), fac varchar(18), almlbl varchar(10), " +
                       "cant integer, sts varchar(1), ser_2_20 varchar(20), rowid_sap integer, stsmat varchar);" +
                    "CREATE TABLE almlbl (almlbl varchar(10), almlbltxt varchar(100), " +
                       "ciudad varchar(50));"; //+
                cmd.ExecuteNonQuery();
            }
        }
        else
            using (SQLiteCommand cmdTxt = new SQLiteCommand(conn))
            {
                cmdTxt.CommandText = "SELECT * from almlbl";
                SQLiteDataReader drT = cmdTxt.ExecuteReader();
                while (drT.Read())
                    dicTxt[drT[0]] = new st() { almlblTxt = drT[1], ciudad = drT[2] };
                drT.Dispose();
                cmdTxt.CommandText = "DELETE FROM almlbl";
                cmdTxt.ExecuteNonQuery();
            }

        using (SQLiteTransaction transac = conn.BeginTransaction())
        {
            using (SQLiteCommand cmd = new SQLiteCommand(conn))
            {
                SQLiteParameter param = new SQLiteParameter();
                SQLiteCommand cmdAux = LibCorp.Lite.buildParmsFromTable("lbl", conn);
                cmd.CommandText = cmdAux.CommandText;
                foreach (SQLiteParameter sp in cmdAux.Parameters)
                    cmd.Parameters.Add(sp);
                long regLei = 0;
                try
                {
                    StreamReader sr = new StreamReader(file, Encoding.Default);
                    sr.ReadLine(); // Ignore title
                    List<object> cols;
                    string line;
                    while (!string.Equals(line = sr.ReadLine(), null)) // Fastest way
                    {
                        if ((++regLei % 1000000) == 0)  //Diff of only 1 or 2 secs if omitted
                            o.show(string.Format(" lbl:{0}", regLei), tbx);
                        cols = new List<object>(line.Split('|')); // Fastest way
                        if (!dicTxt.ContainsKey((string)cols[5])) // diff of only 1 sec if commented
                        {
                            stV.almlblTxt = cols[6];
                            stV.ciudad = cols[8];
                            dicTxt[cols[5]] = stV;
                        }

                        if (!cols[3].Equals("") && cols[3].ToString().Length > 18)
                            cols.Add(cols[3].ToString().Substring(1));
                        else
                            cols.Add(DBNull.Value);

                        cmd.Parameters[0].Value = cols[0];       // alm
                        cmd.Parameters[1].Value = cols[1];       // alm2
                        cmd.Parameters[2].Value = cols[2];       // mat
                        cmd.Parameters[3].Value = cols[3];       // ser
                        cmd.Parameters[4].Value = cols[4];       // fac
                        cmd.Parameters[5].Value = cols[5];       // almlbl
                        cmd.Parameters[6].Value = cols[7];       // cant
                        cmd.Parameters[7].Value = DBNull.Value;  // sts
                        cmd.Parameters[8].Value = cols[10];      // ser_2_20
                        cmd.Parameters[9].Value = DBNull.Value;  // rowid_sap
                        cmd.Parameters[10].Value = cols[9];      // stsmat
                        cmd.ExecuteNonQuery();
                    }

                    foreach (KeyValuePair<object, st> pair in dicTxt)
                    {
                        cmd.CommandText = string.Format("INSERT INTO almlbl VALUES('{0}','{1}','{2}')",
                                pair.Key, pair.Value.almlblTxt, pair.Value.ciudad);
                        cmd.ExecuteNonQuery();
                    }

                    transac.Commit();
                }
                catch (Exception ex)
                {
                    o.notify(string.Format("{0}\n\rSitio->{1}", ex, ex.TargetSite.Name));
                }
                finally
                {
                    conn.Close();
                }
            }

        }
    }

И НЕКОТОРЫЕ ДАННЫЕ ДЛЯ ТЕСТИРОВАНИЯ (УМНОЖЕНИЕ ДО 7 МИЛЛИОНОВ, ПОЖАЛУЙСТА, ВКЛЮЧИТЕ НАЗВАНИЕ):

COD_ALMACEN_SAP|COD_ALMACEN_SAP2|CODIGO_SAP|NRO_SERIE_INICIAL|NRO_INICIO_FACTURA|COD_ALMACEN|NOMBRE_ALMACEN|CANTIDAD|CIUDAD|NOMBRE_ARTICULO

1030|8030|ADAJKIUSD66K|||16|ALMACEN DANSA PRUZ TESULARES|4|BANDA PRUZ|ADA-KI-SD66K ADAPTADOR MAIDIUM SD-66K 1030|8030|BAT-KI-BPA101|||16|ALMACEN LANTA CRUZ TESULARES|5 |BANDA PRUZ|BAT-KI-BPA101 BATERIESAPS 1020|8020|TARGESA/P_PC-GC79|||17|ПЕРРИТОРИАЛЬНЫЙ ЦЕНТР|9|POCHASALTA|TARGESA/P_PC-GC79 TARGESA UNIVERSAL P PC GPRS Y WL 1010|8010|TARJETA/P_PC -GC79|||1014|ТЕРРИТОРИИ СЕВЕР 1|5|PATPAZ|TARGESA/P_PC-GC79 TARJETA UNIVERSAL P PC GPRS Y WL 1060|8060|TARJETA/P_PC-GC79|||1095|ALMACEN SUNY|1|TRONOSAD|TARGESA/ P_PC-GC79 TARGESA UNIVERSAL P ПК GPRS Y WL

enter code here

С Уважением.

С Уважением.


person vizcayno    schedule 09.01.2011    source источник
comment
Привет, Джульетта, я разместил код.   -  person vizcayno    schedule 10.01.2011
comment
Стоит попробовать ограничить размер транзакции. Я видел один пример, когда большое изменение было настолько большим, что потребовалась целая вечность, чтобы записать огромную запись в журнал транзакций. (не опубликовано как ответ, потому что это слухи).   -  person    schedule 15.01.2011
comment
Ян, большое спасибо за ваши комментарии, как вы можете видеть, Sqlite и ADS подчиняются одним и тем же условиям кода, но Sqlite на сегодняшний день является самым быстрым (по крайней мере, при массовой вставке). Я хотел бы знать, как я могу ограничить размер транзакции, используя счетчик в моей программе? С Уважением.   -  person vizcayno    schedule 15.01.2011


Ответы (2)


Прежде всего убедитесь, что в обоих случаях вы используете транзакцию и запрос одинаковы. 2-й убедитесь, что вы вызываете запрос на вставку таким же образом - не создавайте избыточное (для каждого вызова вставки) соединение, запрос или объект адаптера в одном случае, но не в другом. Разница слишком... значительная.

person Przemysław Michalski    schedule 09.01.2011
comment
Тем не менее, разве # SQL Lite не встроен, а сервер (что означает, что вызовы проходят через сетевой уровень)? Я бы предложил распараллелить вставки на 10-20 потоков. - person TomTom; 09.01.2011
comment
Здравствуйте, TomTom, я настроил 20 потоков, но никаких важных улучшений не существует, среднее время составляет 2 минуты на 1 миллион вставленных записей. - person vizcayno; 10.01.2011
comment
UGEEN, я включил код для Sybase и .NET Sqlite; код, который я запускаю на ПК, очень похож, но .NET Sqlite быстрее, чем Sybase. - person vizcayno; 10.01.2011

Попробуйте удалить транзакцию. Транзакции ADS отличаются от традиционных СУБД и требуют больше операций сброса ОС (ADS не использует контрольные точки). Производительность будет намного лучше без транзакции.

Редактировать Заметил, что вы используете локальный сервер, поэтому мои комментарии о транзакции не будут иметь значения. Дэн!

Кроме того, я не знаю, сколько циклов задействовано во втором цикле (INSERT INTO almlbl), но поможет переход на подготовленный запрос с параметрами.

Вполне вероятно, что все эти строки SQLite еще не находятся на диске. Я бы предположил, что многие из них находятся в памяти и не были сброшены.

person Jeremy Mullin    schedule 13.01.2011
comment
Джереми, большое спасибо за ваш ответ, таблицы almlbl очень, очень маленькие по сравнению с lbl. Как видите, и Sqlite, и ADS находятся в одинаковых условиях кода и загружают одинаковое количество записей. Я предполагаю, что ADS пытается быть в безопасности, не теряя данные, поэтому загрузка занимает немного больше времени (7 миллионов записей за 5 или 6 минут больше, чем Sqlite), однако у меня никогда не было проблем с Sqlite. С Уважением. - person vizcayno; 15.01.2011