小编典典

Mysql DELETE(带有NOT IN子选择)不使用索引并出现错误1205(HY000):超出了锁定等待超时;

sql

我的股票报价表有900万行,我需要删除该表上的271k行,为期一天(2018-06-26)。为什么我的DELETE不使用索引并且查询异常终止是有原因的?

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

我如何使此删除工作?

询问:

DELETE FROM `tickers` 
WHERE
      `created_at` between '2018-06-26T00:00:00' and '2018-06-26T23:59:59'
  AND id  NOT IN 
    (SELECT MAX(id) FROM (select * FROM `tickers`) as t2 
          WHERE `created_at` between '2018-06-26T00:00:00' and '2018-06-26T23:59:59'
         GROUP BY
          exchange
         , base_currency
         , quote_currency
         , DATE(created_at)
        );

索引:

index#1 unique index on id
index#2 index on exchange, base_currency, quote_currency, created_at
index#3 index on created_at

解释:

+------+--------------------+------------+-------+--------------------------+--------------------------+---------+------+---------+------------------------------+
| id   | select_type        | table      | type  | possible_keys            | key                      | key_len | ref  | rows    | Extra                        |
+------+--------------------+------------+-------+--------------------------+--------------------------+---------+------+---------+------------------------------+
|    1 | PRIMARY            | tickers    | range | tickers_created_at_index | tickers_created_at_index | 5       | NULL |  554300 | Using where                  |
|    2 | DEPENDENT SUBQUERY | <derived3> | ALL   | NULL                     | NULL                     | NULL    | NULL | 8712002 | Using where; Using temporary |
|    3 | DERIVED            | tickers    | ALL   | NULL                     | NULL                     | NULL    | NULL | 8712002 |                              |
+------+--------------------+------------+-------+--------------------------+--------------------------+---------+------+---------+------------------------------+

使用SELECT而不是DELETE的相同查询有效:

SELECT id FROM `tickers` 
WHERE
      `created_at` between '2018-06-26T00:00:00' and '2018-06-26T23:59:59'
  AND id  NOT IN 
    (SELECT MAX(id) FROM (select * FROM `tickers`) as t2 
          WHERE `created_at` between '2018-06-26T00:00:00' and '2018-06-26T23:59:59'
         GROUP BY
          exchange
         , base_currency
         , quote_currency
         , DATE(created_at)
        );

建议的解决方案1:

DELETE t
FROM tickers t LEFT JOIN
     (SELECT MAX(t2.id) as max_id
      FROM tickers t2 
      WHERE t2.created_at between '2018-06-26T00:00:00' and '2018-06-26T23:59:59'
      GROUP BY exchange, base_currency, quote_currency, DATE(created_at)
     ) t2
     ON t2.max_id = t.id
WHERE t.created_at between '2018-06-26T00:00:00' and '2018-06-26T23:59:59' AND
      t2.max_id IS NULL;

说明建议的解决方案1:

+------+-------------+------------+-------+--------------------------+--------------------------+---------+----------------------+--------+----------------------------------------------+
| id   | select_type | table      | type  | possible_keys            | key                      | key_len | ref                  | rows   | Extra                                        |
+------+-------------+------------+-------+--------------------------+--------------------------+---------+----------------------+--------+----------------------------------------------+
|    1 | PRIMARY     | t          | range | tickers_created_at_index | tickers_created_at_index | 5       | NULL                 | 554300 | Using where                                  |
|    1 | PRIMARY     | <derived2> | ref   | key0                     | key0                     | 5       | dbdevinputspike.t.id |     10 | Using where                                  |
|    2 | DERIVED     | t2         | range | tickers_created_at_index | tickers_created_at_index | 5       | NULL                 | 554300 | Using where; Using temporary; Using filesort |
+------+-------------+------------+-------+--------------------------+--------------------------+---------+----------------------+--------+----------------------------------------------+

提议的解决方案1的结果:

First got: ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction.
Then, noticed that a process was running (SHOW PROCESSLIST;).
Killed the process (KILL <process id>;) and query ran successfully.

提议的解决方案2:

CREATE TEMPORARY TABLE IF NOT EXISTS tickers_temp AS 
(
SELECT id FROM `tickers` 
WHERE
      `created_at` between '2018-06-28T00:00:00' and '2018-06-28T23:59:59'
  AND id  NOT IN 
    (SELECT MAX(id) FROM (select * FROM `tickers`) as t2 
          WHERE `created_at` between '2018-06-28T00:00:00' and '2018-06-28T23:59:59'
         GROUP BY
          exchange
         , base_currency
         , quote_currency
         , DATE(created_at)
        )
)   ;


DELETE FROM `tickers` WHERE id IN (SELECT id FROM `tickers_temp`);

提议的解决方案2的结果:

Running for a looong time. Killed the process.

阅读 208

收藏
2021-05-16

共1个答案

小编典典

尝试使用join

DELETE t
    FROM tickers t LEFT JOIN
         (SELECT MAX(t2.id) as max_id
          FROM tickers t2 
          WHERE t2.created_at between '2018-06-26T00:00:00' and '2018-06-26T23:59:59'
          GROUP BY exchange, base_currency, quote_currency, DATE(created_at)
         ) t2
         ON t2.max_id = t.id
    WHERE t.created_at between '2018-06-26T00:00:00' and '2018-06-26T23:59:59' AND
          t2.max_id IS NULL;
2021-05-16