我正在尝试创建一个数据库(在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();
}
答案 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约束),则这些查找将更快。