优化sqlite插入查询

时间:2017-02-16 01:46:51

标签: c# mysql sqlite

我正在尝试创建一个数据库(在C#中使用SQLite),其中包含一个用于存储句子的表,一个用于存储这些句子中使用的每个单词的表,以及一个将单词与句子相关联的联结表他们出现在。 然后,我试图用超过1500万个句子填充数据库。我估计我的代码中有大约1.5亿次插入。 现在,我的代码每秒只执行几百个句子,这将花费很长时间来完成这个庞大的数据集。我怎样才能让它更快?

我尝试将ENTIRE事件放在一个事务中,但我不确定这是否可以因为大量数据而起作用。所以我为每个句子使用一个交易。

表:

CREATE TABLE sentences ( sid INTEGER NOT NULL PRIMARY KEY, sentence TEXT ); 
CREATE TABLE words ( wid INTEGER NOT NULL PRIMARY KEY, dictform TEXT UNIQUE); 
CREATE TABLE sentence_words( sid INTEGER NOT NULL, wid INTEGER NOT NULL, CONSTRAINT PK_sentence_words PRIMARY KEY ( sid, wid ), FOREIGN KEY(sid) REFERENCES Sentences(sid), FOREIGN KEY(wid) REFERENCES Words(wid));

代码:

while ((input = sr.ReadLine()) != null) //read in a new sentence
        {
            tr = m_dbConnection.BeginTransaction();
            sql = "INSERT INTO sentences (sentence) VALUES(@sentence)";
            cmd = new SQLiteCommand(sql, m_dbConnection);
            cmd.Parameters.AddWithValue("@sentence", input);
            cmd.ExecuteNonQuery();

            dict_words = jutils.onlyDict(input); //convert all words to their 'dictionary form'
            var words = dict_words.Split(' ');
            foreach (var wd in words) //for each word
            {
                sql = "INSERT or IGNORE INTO words (dictform) VALUES(@dictform)";
                cmd = new SQLiteCommand(sql, m_dbConnection);
                cmd.Parameters.AddWithValue("@dictform", wd);
                cmd.ExecuteNonQuery();

                sql = "INSERT or IGNORE INTO sentence_words (sid, wid) VALUES((SELECT sid FROM sentences WHERE sentence = @sentence), (SELECT wid FROM words WHERE dictform = @dictform))";
                cmd = new SQLiteCommand(sql, m_dbConnection);
                cmd.Parameters.AddWithValue("@sentence", input);
                cmd.Parameters.AddWithValue("@dictform", wd);
                cmd.ExecuteNonQuery();
            }
            tr.Commit();
        }

3 个答案:

答案 0 :(得分:2)

总是,在处理如此大的数据时,我们必须避免“逐个”的SQL任务。

就我而言,(如果内存没有负担),将数据加载到DataTable中并根据需要进行操作(使用LINQ),最后使用SqlBulkCopy。

还有SqlBulkUpdate,但是由SQL 2008支持的私人作者创建。 如果在2008年,我们仍然可以快速执行此操作,但必须创建临时SQL表并使用UPDATE Join命令。

SqlBulkCopy真的很快就像秒。

答案 1 :(得分:0)

您可以按一定数量的行进行分组

int lines = -1; 
int group = 500;
while ((input = sr.ReadLine()) != null) 
    {
     lines++;
     if (lines%group == 0) {
        tr = m_dbConnection.BeginTransaction();
        }

并提交每个小组

     if (lines%group == group-1) {
        tr.Commit();
        }
    }
if (lines%group >= 0 && lines%group <  group-1) {
    tr.Commit();
    }

我有一些旧案例,我被迫使用.Net 4.0和BulkCopy不是一个选项,因为它的异步实现。

答案 2 :(得分:0)

将整个事情放在一个交易中。 (回滚日志存储由事务更改的任何页面的旧版本,因此对于空数据库,它不能变大。)

此外,sentence值的所有搜索都是低效的,因为数据库必须遍历整个表。如果该列具有索引(显式地或隐式地具有UNIQUE约束),则这些查找将更快。