【发布时间】:2012-03-02 12:54:08
【问题描述】:
我需要一些关于更新 MySql 数据库中大量记录的建议。我目前正在将大量单词及其后缀(后缀数组)存储到数据库中,导致行数约为 430 万。每条记录包含主键id,实际单词word,单词在document中的文档,单词在文档中的偏移量'offset',判断记录是否为整个单词的标志或不是flag 和link 到下一条记录,word 具有相同的值。每条记录都使用-1的链接值进行初始化。
这是我当前用于更新数据库中链接的代码:
public void Link(object c)
{
DBConnection conn = (DBConnection)c;
rowcount = conn.GetRowCount();
string word;
int link;
List<Record> recordsList = new List<Record>();
List<Record> recordsMatched = new List<Record>();
for (int i = 0; i < rowcount; i++)
{
recordsList.AddRange(conn.ReadQuery("SELECT * FROM csa2018.words WHERE id = " + i));
word = recordsList[0].Word;
link = recordsList[0].Link;
recordsMatched = conn.ReadQuery("SELECT * FROM csa2018.words WHERE word = '" + word + "'");
for(int j = 0; j < recordsMatched.Count-1; j++)
{
if (recordsMatched[j].Link == -1)
{
conn.WriteQuery("UPDATE csa2018.words SET link = " + recordsMatched[j + 1].Id + " WHERE id = " + recordsMatched[j].Id);
}
else
{
break;
}
linkedRecords++;
}
linkedRecords++;
recordsMatched.Clear();
recordsList.Clear();
}
Form1.linkingFinished = true;
}
总的来说,它在查找频繁重复的单词时具有良好的性能;但是在大约 60% 时,性能会下降,因为大多数剩余的单词都是唯一的。 我的猜测是这个查询:
recordsMatched = conn.ReadQuery(
"SELECT * FROM csa2018.words WHERE word = '" + word + "'");
不应该这样,因为它每行都被调用一次。有没有更好的方法,比如使用存储过程?
P.S.:ReadQuery 方法使用提供的查询读取行并构造 Record 对象并将每条记录添加到 List<Record>。
这就是我的数据库的样子:
CREATE TABLE words ( id int(11) NOT NULL, word varchar(45) NOT NULL,
document varchar(45) NOT NULL, offset int(11) NOT NULL, flag int(11) NOT NULL,
link int(11) DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
【问题讨论】:
-
请发布表创建详细信息。我们需要它来查看您在表上定义了哪些索引,以及您使用了哪些列数据类型。在 mysql 命令行中,您可以通过运行方便地获取此信息:
SHOW CREATE TABLE csa2018.words -
首先,给单词添加索引。其次,您应该在查询中使用参数。见stackoverflow.com/questions/652978/…
-
大行数和嵌套循环的结合势必会导致问题;某种字典会更好——但 IMO 最大的问题是 SQL 查询太多;批量操作最好通过基于集合的 SQL 批量完成。不是基于行的。
-
那么我怎样才能获取特定单词的所有实例并一次性设置它们的链接呢?我在 SQL 方面没有太多经验。
-
在 SQL 中使用参数会提高性能。每个 SQL 语句都应该在循环之外构建。转到:dev.mysql.com/doc/refman/5.0/es/… 并搜索 '(?val)'