为什么插入我的 MySQL table 需要这么长时间

Why are INSERTS into my MySQL table taking so long

我正在构建一个 MySQL 帐户数据库。我有一个从 json 文件导入整个数据库的例程。该例程在单个事务中运行, 删除每个 table 的所有记录,调用:

ALTER TABLE <tablename> AUTO_INCREMENT = 1

在每个 table 上,然后使用像

这样的 INSERT 语句从数据中加载 table
INSERT INTO Journal (idJournal, DocumentId, AccountId, Memo, JournalNum,
 Amount, Outstanding, Cleared, NameAddressId) 
 VALUES (11423, 4454, 14, 'Deposit', 1, 53.33, 53.33, 'X', 292)

(注意table的加载顺序是正确的,所以相关记录已经存在)。

我发现插入语句需要很长时间(有些长达 70 毫秒),尤其是与从 mysqldump 加载相同数据相比。

我能做些什么来加快速度(除了改用 mysqldump 之外,我不想这样做,因为我希望备份数据采用 json 格式)?

Table定义:

  CREATE TABLE IF NOT EXISTS `accounts`.`Journal` (
    `idJournal` INT NOT NULL AUTO_INCREMENT,
    `DocumentId` INT NOT NULL,
    `AccountId` INT NOT NULL,
    `Memo` VARCHAR(45) NULL,
    `JournalNum` INT NOT NULL,
    `Amount` DECIMAL(10,2) NOT NULL,
    `Outstanding` DECIMAL(10,2) NOT NULL DEFAULT 0,
    `Cleared` CHAR(1) NOT NULL,
    `NameAddressId` INT NULL,
    PRIMARY KEY (`idJournal`),
    INDEX `fk_Journal_Document1_idx` (`DocumentId` ASC),
    INDEX `fk_Journal_Account1_idx` (`AccountId` ASC),
    UNIQUE INDEX `Document_Num` (`DocumentId` ASC, `JournalNum` ASC),
    INDEX `fk_Journal_NameAddress1_idx` (`NameAddressId` ASC),
    CONSTRAINT `fk_Journal_Document1`
   FOREIGN KEY (`DocumentId`)
   REFERENCES `accounts`.`Document` (`idDocument`)
   ON DELETE NO ACTION
   ON UPDATE NO ACTION,
    CONSTRAINT `fk_Journal_Account1`
   FOREIGN KEY (`AccountId`)
   REFERENCES `accounts`.`Account` (`idAccount`)
   ON DELETE NO ACTION
   ON UPDATE NO ACTION,
    CONSTRAINT `fk_Journal_NameAddress1`
   FOREIGN KEY (`NameAddressId`)
   REFERENCES `accounts`.`NameAddress` (`idNameAddress`)
   ON DELETE NO ACTION
   ON UPDATE NO ACTION)
  ENGINE = InnoDB

执行多个插入时,在单个语句中插入多行会提高性能,尤其是当您有很多二级索引时:

INSERT INTO Journal (idJournal, DocumentId, AccountId, Memo, JournalNum,
  Amount, Outstanding, Cleared, NameAddressId) 
VALUES (11423, 4454, 14, 'Deposit', 1, 53.33, 53.33, 'X', 292),
       (11424, 4455, 15, 'Deposit', 1, 23.33, 23.33, 'X', 293),
       ...

这样,索引只更新一次(在语句末尾),而不是在每次插入之后。

如果您的数据库增长超过 1GB,您将遇到问题,因为您将达到 max_allowed_packet 的限制。在这种情况下,您可能必须将其分解为多个查询。

当您说 "drops all the records" 时,我希望您的意思是删除 table 或截断 table 而不是实际删除所有记录。

这适用于 "no" 中断 table 的使用:

  1. CREATE TABLE new LIKE real;
  2. 通过批量插入(或其他)加载 new
  3. RENAME TABLE real TO old, new TO real; -- 瞬时和原子
  4. DROP TABLE old;

没有截断,没有AUTO_INCREMENT=1