【问题标题】:How can I optimize MySQL query for update?如何优化 MySQL 查询以进行更新?
【发布时间】:2013-02-14 23:00:33
【问题描述】:

我有一个包含 300 000 条记录的表。在这个表中有重复的行,我想更新列“标志”

表格

------------------------------------
|number | flag | ... more column ...|
------------------------------------
|ABCD   |  0   | ...................|
|ABCD   |  0   | ...................|
|ABCD   |  0   | ...................|
|BCDE   |  0   | ...................|
|BCDE   |  0   | ...................|

我使用此查询来更新“标志”列:

UPDATE table i 
INNER JOIN (SELECT number FROM table
            GROUP BY number HAVING count(number) > 1 ) i2
ON i.number = i2.number
SET i.flag = '1'

对于这 300 000 条记录,此查询的工作非常缓慢(超过 600 秒)。

如何优化这个查询?

我的表结构

CREATE TABLE IF NOT EXISTS `inv` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `pn` varchar(10) NOT NULL COMMENT 'Part Number',
  `qty` int(5) NOT NULL,
  `qty_old` int(5) NOT NULL,
  `flag_qty` tinyint(1) NOT NULL,
  `name` varchar(60) NOT NULL,
  `vid` int(11) NOT NULL ,
  `flag_d` tinyint(1) NOT NULL ,
  `flag_u` tinyint(1) NOT NULL ,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `pn` (`pn`),
  KEY `name` (`name`),
  KEY `vid` (`vid`),
  KEY `pn_2` (`pn`),
  KEY `flag_qty` (`flag_qty`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=0 ;

如果“名称”重复,我想更新 flag_qty

【问题讨论】:

  • 什么是表结构?此表是否有可用的主键?
  • 设置这个标志的目的是什么?您是否正在根据此标志进行进一步处理?
  • 所有其他列的数据是否也是重复的,或者它们是否具有不同的值?我问这些问题是因为我怀疑您正在尝试做的事情有更好的解决方案吗?这是一次性重复数据删除过程还是经常发生?你如何结束重复?如果您不想重复,为什么number 不是主键(或至少有一个唯一键)?
  • 其他列的数据不同。数字匹配,但另一列(“...更多列...”)中的信息不重复。出于这个原因,我想更新字段标志。

标签: mysql optimization


【解决方案1】:

如果您还没有在 number 上的索引,您应该添加一个 -

CREATE INDEX table_number ON table (number);

更新试试这个 -

UPDATE inv t1
INNER JOIN inv t2
    ON t1.name = t2.name
    AND t1.id <> t2.id
SET t1.flag_qty = 1;

您可以通过直接将此数据选择到另一个表中而不是先更新此标志来创建仅包含重复项的表。

INSERT INTO duplicate_invs
SELECT DISTINCT inv1.*
FROM inv AS inv1
INNER JOIN inv AS inv2
    ON inv1.name = inv2.name
    AND inv1.id < inv2.id

如果您能解释从inv 表中删除哪些行的逻辑,那可能是整个过程可以一步完成。

【讨论】:

  • 在这种情况下,请发布SHOW INDEXES FROM table_name 的输出。我在测试中针对 3M 行运行了您的查询,它在我的笔记本电脑上仅用了 1 秒就返回了。添加完整的表结构(SHOW CREATE TABLE table_name 的输出)可能会有所帮助。
  • 我为我的表添加了一个sql结构。
【解决方案2】:

获取 MySQL 到 EXPLAIN 的查询给你。然后你会看到索引会改善什么。

【讨论】:

    【解决方案3】:

    EXPLAIN 会告诉你哪里速度很慢,这里有一些想法,如何提高性能:

    • 添加索引
    • 使用 InnoDB 外键
    • 将查询拆分为 2 个,并在您使用的语言中分别处理它们。
    • 在 MySQL 程序中编写相同的想法(不确定,这是否会很快)。

    【讨论】:

      【解决方案4】:

      我会使用临时表。 1.) 将所有相关记录选择到临时表中,在 id 上设置 INDEX。 2.) 使用类似的方法更新表格

      UPDATE table i, tmp_i
      SET i.flag = '1'
      WHERE i.id = tmp_i.id
      

      【讨论】:

        【解决方案5】:

        你可以试试(假设是VB.net,但可以用任何语言实现)。

        Dim ids As String =   Cmd.ExectueScalar("select group_concat(number) from (SELECT number FROM table  GROUP BY number HAVING count(number) > 1)")
        

        在获得 ID 列表(逗号分隔)后,然后使用

        UPDATE i  
        SET i.flag = '1' 
        WHERE i.number in ( .... )
        

        它也可能很慢,但第一个 - SELECT 不会锁定您的数据库和复制等。UPDATE 会更快。

        【讨论】:

          猜你喜欢
          • 2017-12-30
          • 1970-01-01
          • 2011-06-09
          • 1970-01-01
          • 2013-07-12
          • 1970-01-01
          • 1970-01-01
          • 2021-06-29
          • 1970-01-01
          相关资源
          最近更新 更多