MySQL UPDATE 性能...更快

Posted

技术标签:

【中文标题】MySQL UPDATE 性能...更快【英文标题】:MySQL UPDATE Performance ...which is faster 【发布时间】:2018-08-14 15:26:46 【问题描述】:

假设我有以下 2 个 mysql 表:

CREATE TABLE Table1
(
    IndexNumber INT UNSIGNED NOT NULL AUTO_INCREMENT,
    FieldOne TINYINT UNSIGNED NOT NULL,
    FieldTwo VARCHAR(180) NOT NULL,
    FieldThree DATE,
    FieldFour INT,
    PRIMARY KEY (IndexNumber, FieldThree),
    UNIQUE KEY (FieldOne, FieldTwo)
) ENGINE=InnoDB;

CREATE TABLE Table2
(
    IndexNumber INT UNSIGNED NOT NULL,
    FieldFive TINYINT UNSIGNED NOT NULL,
    FieldSix TINYINT UNSIGNED NOT NULL,
    FOREIGN KEY (IndexNumber) REFERENCES Table1 (IndexNumber),
    KEY (IndexNumber),
    KEY (FieldFive, FieldSix)
) ENGINE=InnoDB;

现在,我想做几个查询来检索一些匹配的记录,并且在每个 SELECT 查询之后我想更新匹配的记录,以便明天才能再次检索它们。

SELECT 查询如下:

SELECT table1.fieldone, 
       table1.fieldtwo 
FROM   table2 
       INNER JOIN table1 
               ON table2.indexnumber = table1.indexnumber 
WHERE  table2.fieldfive = 1 
       AND table2.fieldsix = 2; 

SELECT table1.fieldone, 
       table1.fieldtwo 
FROM   table2 
       INNER JOIN table1 
               ON table2.indexnumber = table1.indexnumber 
WHERE  table2.fieldfive = 1 
       AND table2.fieldsix = 3 
       AND table1.fieldthree <> Curdate(); 

我的问题是——在每个 select 查询之后更新匹配记录以使下一个 SELECT 查询不匹配它的最快方法是什么?

我可以在 SELECT 查询中检索“IndexNumber”字段,然后我可以按如下方式执行 UPDATE 查询,传入“IndexNumber”字段值:

UPDATE table1 
SET    fieldthree = Curdate(), 
       fieldfour = (fieldfour + 1) 
WHERE  indexnumber IN (...indexnumbers...)ve = 1 
AND    table2.fieldsix = 3 
AND    table1.fieldthree <> curdate();

或者我可以从 SELECT 查询中重复 WHERE,并希望缓存使其更快:

UPDATE table2 
       INNER JOIN table1 
               ON table2.indexnumber = table1.indexnumber 
SET    table1.fieldthree = Curdate(), 
       table1.fieldfour = ( table1.fieldfour + 1 ) 
WHERE  table2.fieldfive = 1 
       AND table2.fieldsix = 2; 

UPDATE table2 
       INNER JOIN table1 
               ON table2.indexnumber = table1.indexnumber 
SET    table1.fieldthree = Curdate(), 
       table1.fieldfour = ( table1.fieldfour + 1 ) 
WHERE  table2.fieldfive = 1 
       AND table2.fieldsix = 3 
       AND table1.fieldthree <> Curdate() 
       AND table1.fieldthree <> Curdate(); 

请注意,UPDATE 查询将在 SELECT 查询之后和下一个 SELECT 查询执行之前立即执行。

这两种方法哪一种更有效?

【问题讨论】:

TLDR。你为什么不测试这两种方法而不是问我们? 向我们展示数据库架构、示例数据、当前和预期输出。请阅读How-to-Ask 这里是START 了解如何提高问题质量并获得更好答案的好地方。 How to create a Minimal, Complete, and Verifiable example 尝试在rextester.com 中创建示例。 现在我读到并不清楚更新是发生在 Query1 和 Query2 之间还是在 Query2 之后。也不清楚你想做什么,因为没有任何数据或预期的结果。 最快通常是理论上的,直到您使用 your 系统配置在 your 硬件上对其进行测试。对于在 128GB 高度优化的 64 核 MySQL 服务器上工作的人可能会在更适中的系统上表现得很糟糕。 好吧,很公平,我希望有人能有见解,但一旦我运行了一些测试,我会回来发布更新...... 【参考方案1】:

首先,当您在 InnoDB 表中有 id .. AUTO_INCREMENT 时,PRIMARY KEY(id)PRIMARY KEY(id, other_col) 之间没有区别。

第二,你的table2没有明确的PRIMARY KEY;这是不好的'。将为您提供隐藏的 PK,但它不会像明确拥有自己的那样“好”。

对于这个选择:

    INNER JOIN  table1  ON table2.indexnumber = table1.indexnumber
    WHERE  table2.fieldfive = 1
      AND  table2.fieldsix = 2;

它将以table2 开头,因为有过滤(WHERE)。最佳索引是

table2:  INDEX(fieldfive, fieldsix,   -- in either order
               indexnumber)           -- to make the index "covering"
table1:   (indexnumber)               -- it's already the PK, so good

对于这个选择:

    INNER JOIN  table1  ON table2.indexnumber = table1.indexnumber
    WHERE  table2.fieldfive = 1
      AND  table2.fieldsix = 3
      AND  table1.fieldthree <> Curdate();  -- not easy to optimize

再次,它将从 table2 开始,并且与上面相同的索引是最佳的。另一个注意事项...由于给定的indexnumber(当JOINing)在table1 中最多有1 行,所以&lt;&gt; 会过滤掉一些行。 没有需要调整任何索引。

(您的第一个UPDATE 无效,因为它提到fieldsix 而没有提及table2。)

第二个UPDATE 几乎涵盖了讨论SELECT

第三个UPDATE 可能会由于日期测试而命中更少的行,但这意味着它与第二个UPDATE 相同——因为它不会总是增加@987654342 @。

【讨论】:

以上是关于MySQL UPDATE 性能...更快的主要内容,如果未能解决你的问题,请参考以下文章

Mysql 存储引擎中InnoDB与Myisam的主要区别

Mysql 存储引擎中InnoDB与MyISAM差别(网络整理)

Mysql 存储引擎中InnoDB与Myisam的主要区别

加快 UPDATE 性能 MySQL

mysql innodb myisam 主要区别与更改方法

MySQL降低insert, update, delete的优先级来优化性能