【问题标题】:Improving performance of SQL SELECT in C#在 C# 中提高 SQL SELECT 的性能
【发布时间】:2012-03-02 12:54:08
【问题描述】:

我需要一些关于更新 MySql 数据库中大量记录的建议。我目前正在将大量单词及其后缀(后缀数组)存储到数据库中,导致行数约为 430 万。每条记录包含主键id,实际单词word,单词在document中的文档,单词在文档中的偏移量'offset',判断记录是否为整个单词的标志或不是flaglink 到下一条记录,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&lt;Record&gt;

这就是我的数据库的样子:

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)'

标签: c# mysql database


【解决方案1】:

如果我正确理解了您的代码,那么这个单一的 sql 语句应该可以完成这项工作:

UPDATE  csa2018.words as w1 

    left join 

    (select w2.id as id, min(w3.id) as linked_to 
    from    csa2018.words w2, csa2018.words w3 
    where   w2.word = w3.word and 
            w3.id > w2.id limit 1) w4

    on (w1.id = w4.id)

SET     w1.link = IFNULL(w4.linked_to, -1)

内部选择语句给出从一个数据集到链接数据集的映射。您应该观察 select 语句的结果,看看是否一切正常。

【讨论】:

  • 不幸的是,这段代码运行起来很慢,10 分钟内甚至没有达到 1%。也许是因为我改变了数据库引擎?我在文本字段上添加了一个索引并从 InnoDB 切换到 MyISAM,它现在工作得更快了。还是谢谢!
  • 您可以尝试:“选择 w2.id 作为 id,w3.id 作为linked_to from csa2018.words w2, csa2018.words w3 where w2.word = w3.word and w3.id > w2. id order by w3.id limit 1" 作为内部选择语句(我认为这不应该更好)
  • 要优化 InnoDB,您可以尝试在更新期间禁用键和约束。搜索“ALTER TABLE [tablename] DISABLE KEYS;”和“SET FOREIGN_KEY_CHECKS=0;”。但我认为这也不应该提供更好的性能,所以试试吧。
猜你喜欢
  • 2014-06-11
  • 2016-04-19
  • 2016-08-25
  • 1970-01-01
  • 2018-09-06
  • 1970-01-01
  • 2014-03-23
  • 2013-07-06
  • 1970-01-01
相关资源
最近更新 更多