在 MySQL InnoDB 中替换为表非常慢

Vic*_*tor 4 mysql mariadb

使用 MySQL(准确地说是 MariaDB)。我有以下脚本需要每隔一天运行一次来​​更新我的数据库,但它慢得令人无法忍受。要更新的每个表都需要运行数小时。这是一个shell脚本:

CMD_MYSQL="${MYSQL_DIR}mysql  --local-infile=1 --default-character-set=utf8 --protocol=${MYSQL_PROTOCOL} --port=${MYSQL_PORT} --user=${MYSQL_USER} --pass=${MYSQL_PASS} --host=${MYSQL_HOST} --database=${MYSQL_DB}"

### Update MySQL Data ###
## table name are lowercase
tablename=`echo $FILE | tr "[[:upper:]]" "[[:lower:]]"`
echo "Uploading ($FILE) to ($MYSQL_DB.$tablename) with REPLACE option..."
## let's try with the REPLACE OPTION
$CMD_MYSQL --execute="LOAD DATA LOCAL INFILE '$FILE.txt' REPLACE INTO TABLE $tablename CHARACTER SET utf8 FIELDS TERMINATED BY '|' IGNORE 1 LINES;"
## we need to erase the records, NOT updated today
echo "erasing old records from ($tablename)..."
$CMD_MYSQL --execute="DELETE FROM $tablename WHERE datediff(TimeStamp, now()) < 0;"
Run Code Online (Sandbox Code Playgroud)

您可以安全地忽略在文件中其他地方设置的一些变量。在$FILE通常txt的文件被分隔|。每行代表一条记录,例如:

AirportID|AirportCode|AirportName|Latitude|Longitude|MainCityID|CountryCode
6024358|DME|Moscow, Russia (DME-Domodedovo Intl.)|55.414495|37.899907|2395|RU
6024360|DMM|Dammam, Saudi Arabia (DMM-King Fahd Intl.)|26.468075|49.796824|180543|SA
Run Code Online (Sandbox Code Playgroud)

该脚本在现有数据库上运行,在该数据库中可以找到旧记录。然后检查其上次更新日期,并执行REPLACE INTO,但对于 100MBtxt文件通常需要 8 小时。

我怎样才能显着提高速度?

Sae*_*eed 5

此问题影响 InnoDB (4.1+) 的所有版本。在 InnoDB 中替换重复项太慢了。这是 MyISAM 优越的地方。MyISAM 耗时 0.05 秒。

原因是 InnoDB 中重复键错误处理依赖于 undo log 和语句回滚: 1. 锁定记录。2. 写update_undo log 用于删除标记记录。3. 写入insert_undo日志以插入记录。4. 尝试插入新记录。5. 注意重复。6、回滚步骤3和2中写入的undo log。

这是 MySQL 中的一个问题,截至 2019 年 9 月尚未在任何版本中修复:https : //bugs.mysql.com/bug.php? id =71507

他们计划在第 2 步检测重复。这将避免在这种情况下发生任何回滚。

这里有2个建议:

  1. 如果适用,请使用 MyISAM
  2. 使用查询,例如 INSERT INTO ... ON DUPLICATE KEY UPDATE ...