【问题标题】:Insert data to Mysql getting slower and slower向Mysql插入数据越来越慢
【发布时间】:2016-09-24 08:24:03
【问题描述】:

我需要每分钟向本地数据库插入 388 个数据。 起初,当表为空时,我只需要 5 秒即可插入数据库。

但是当表变大时,当行数达到 1,026,558 时,程序效率会减慢到一分钟以上。

并且CPU的使用率是100%。这很不寻常。

这是我的代码:

public static void dataToDB(String[] routeIDArray,String[] levelArray,String[] valueArray,String[] travelTimeArray, int amountOfData)
    {
        MySqlConnection con = new MySqlConnection(connStr);
        MySqlCommand cmd = null;
        MySqlDataReader rdr = null;
        String sqlCmd, updateSqlCmd = "UPDATE `datetimetable` SET ";
        for(int counter = 0; counter < amountOfData; counter++)
        {
            sqlCmd = "ALTER TABLE `datetimetable` ADD COLUMN IF NOT EXISTS `" + routeIDArray[counter] + "` INT NULL;"
                + "INSERT INTO `roadvalue`.`data` (`level`,`value`,`traveltime`) VALUES ("
                + levelArray[counter] + ","
                + valueArray[counter] + ","
                + travelTimeArray[counter] + ");"
                + "SELECT LAST_INSERT_ID() FROM `data`;";
            cmd = new MySqlCommand(sqlCmd, con);
            con.Open();
            rdr = cmd.ExecuteReader();
            rdr.Read();
            updateSqlCmd += "`" + routeIDArray[counter] + "` = " + rdr[0] + ",";
            rdr.Close();
        }
        updateSqlCmd = updateSqlCmd.TrimEnd(',');
        updateSqlCmd += " WHERE EXISTS (SELECT * WHERE dateTime = '" + dateTime.ToString("yyyy-MM-dd HH:mm:00") + "');";
        cmd = new MySqlCommand(updateSqlCmd, con);//update data key to datetimetable
        cmd.ExecuteNonQuery();
        Console.WriteLine("Done.");
        con.Close();
    }
    public static void checkDateTimeExisted()
    {
        MySqlConnection con = new MySqlConnection(connStr);
        MySqlCommand cmd;
        String sqlCmd;
        sqlCmd = "INSERT INTO `datetimetable` (`dateTime`) SELECT * FROM (SELECT '" + dateTime.ToString("yyyy-MM-dd HH:mm:00")
                     + "') AS tmp WHERE NOT EXISTS(SELECT `dateTime` FROM `datetimetable` WHERE `dateTime` = '" + dateTime.ToString("yyyy-MM-dd HH:mm:00") + "') LIMIT 1; ";

            con.Open();
            cmd = new MySqlCommand(sqlCmd, con);
            cmd.ExecuteNonQuery();
            con.Close();
    }

Mysql Engine 是 InooDB,表“data”有一个 Auto_Increment 主键,表“datetimetable”有一个 Auto_Increment 主键和一个不重复的 datetime 作为索引。

我做错了什么?

【问题讨论】:

  • routeIDArray[counter] 有多少个不同的值?尤其是对于大表,更改它们是一个巨大的、巨大的、巨大的性能杀手——你应该尝试一种不同的方式来实现你想要实现的任何目标
  • 我使用Thread运行dataToDB(),每50个数据运行一个线程。
  • 所以我理解正确,不是让您的代码线程安全,而是按需为每个线程创建一个新列?您可以尝试在一个线程中运行所有插入,没有额外的列,使用准备好的语句和事务内部。应该会给您带来巨大的性能提升。哦:打开/关闭你的数据库连接一次。这也是一个巨大的杀手。
  • 我的第一个想法是一次性插入所有数据(insert into roadvalue.data(...) values (a,b,c),(a,b,d),(...)),然后更新你的datetimetable(你甚至不需要准备它,数据是在roadvalue.data 中,加入它。作为一般规则:您不想为新的 routeid 添加列。您想更改数据模型以在行中使用它们。
  • 我删除了alter命令,但是效果还是很慢。

标签: c# mysql database mariadb


【解决方案1】:

我找到了答案,命令“SELECT LAST_INSERT_ID() FROM data;”应该添加 LIMIT 1 否则它会得到所有的 ID 杀死性能。

【讨论】:

    【解决方案2】:

    不要在循环中使用ALTER TABLE -- 提前计划并在开始之前提供所有列。

    不要在单个字符串中使用多个语句。这具有安全隐患等。

    当(我认为)一个简单的WHERE 可以工作时,不要使用WHERE EXISTS...

    如果有UNIQUE(datetime),那么最后的INSERT就可以简单了

    INSERT IGNORE INTO datetimetable
        (datetime)
        VALUE
        ('...');
    

    除非您需要LAST_INSERT_ID(),否则请执行批量插入。 LIMIT 1 应该不是必需的。

    不要“规范化”日期时间值;它只会减慢速度。只需将日期时间原样放在主表中即可。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-05
      • 1970-01-01
      • 2021-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-23
      • 2023-03-12
      相关资源
      最近更新 更多