为什么我的MySQL表中的插入要花这么长时间

为什么我的MySQL表中的插入要花这么长时间,mysql,optimization,Mysql,Optimization,我正在建立一个MySQL帐户数据库。我有一个从json文件导入整个数据库的例程。该例程在单个事务中运行, 删除每个表中的所有记录,调用: ALTER TABLE <tablename> AUTO_INCREMENT = 1 (请注意,表是按正确的顺序加载的,因此相关记录已经存在) 我发现insert语句花费了很长时间(有些长达70毫秒),尤其是与从mysqldump加载相同的数据相比 我可以做些什么来加速这个过程(除了使用mysqldump,我不想这样做,因为我希望备份数据是jso

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

ALTER TABLE <tablename> AUTO_INCREMENT = 1
(请注意,表是按正确的顺序加载的,因此相关记录已经存在)

我发现insert语句花费了很长时间(有些长达70毫秒),尤其是与从mysqldump加载相同的数据相比

我可以做些什么来加速这个过程(除了使用mysqldump,我不想这样做,因为我希望备份数据是json格式的)

表定义:

  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,您将遇到问题,因为您将达到1GB的限制。在这种情况下,您可能需要将其分解为多个查询

当您说“删除所有记录”时,我希望您的意思是删除表或截断表,而不是实际删除所有记录。

这在“无”中断表使用的情况下起作用:

  • 像real一样创建新表
  • 通过成批插入(或其他方式)加载新的
  • 将表格real重命名为old,将new重命名为real--瞬时和原子
  • 删除旧表

  • 没有TRUNCATE,没有AUTO_INCREMENT=1

    所以你对json文件的每一行都发出一个单独的insert查询?我不禁想知道为什么有人会想到尝试这样的任务。MySQL有很多现成的功能-为什么要自己开发呢?!因为我没有严格地进行备份,所以更允许将数据导出和导入到json格式。有一些问题-MySql文档说,如果有外键(有外键),TRUNCATE TABLE会一次删除一行。对于多个插入,这不允许在某些记录中缺少字段,而在其他记录中则不允许。您可以命名插入中的所有列,并根据需要使用
    NULL
    DEFAULT
    。我很高兴您正在阅读文档,并看到有比使用
    DELETE
    清除表更有效的方法。如果中途回滚事务(例如,由于输入数据无效),会发生什么情况?一切都会像以前一样吗?或者是截断或删除,如果我使用的话)不利于事务处理?关于TRUNCATE的文档在这一点上有点不清楚。您不能回滚DROP或TRUNCATE,因为它们执行before和after.OK,所以返回到我删除所有记录的原始代码。ALTER TABLE呢?事务友好吗?听起来很有趣!如果在处理了一些表后回滚事务,而不是在处理了其他表后回滚事务,会发生什么情况?数据库是否会处于与开始时相同的状态?这是一个问题。我遗漏了一些细节:添加
    BEGIN
    <步骤2前后的代码>提交
    ,加上检查错误的代码和适当时的
    回滚
    (而不是
    提交
    )。请注意,这样的事务不能包括
    CREATE
    RENAME
    DROP
    ,因此只有步骤2可以有begin…commit。我想我可以将所有数据加载到并行表中,commit,然后执行一次重命名来重命名所有数据,然后执行一系列DROP。我必须在开始时添加一些DROP IF EXIST语句,以防在删除完成之前断电。顺便说一句,如果在“即时”重命名过程中断电,会发生什么情况?请小心不要在一个“开始..提交”中有大量活动。由于您有一个回退(通过重新加载),因此在加载过程中几乎不需要任何事务完整性。是的,在重命名过程中可能会出现问题。这是苗条的,我怀疑会有tmp表左右。重新运行加载脚本可能会遇到额外/丢失的表,需要手动进行一些修复。所有表都可以(应该)在一次重命名中重命名。您现在拥有的设备更容易发生电源故障。
    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),
           ...