The*_*aom 5 mysql performance delete explain mysql-5.7 query-performance
我有一个大约有 3000 万行的表(很快就会增加两倍/三倍),我必须在其中进行定期更新。表结构如下:
id,
cookie_id VARCHAR(45),
country VARCHAR(45),
category VARCHAR(45),
other_non_relevant_columns
Run Code Online (Sandbox Code Playgroud)
索引看起来像这样:
SHOW INDEX FROM data;
+-------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| data | 0 | PRIMARY | 1 | id | A | 24767570 | NULL | NULL | | BTREE | | |
| data | 1 | cookie_index | 1 | cookie_id | A | 14440214 | NULL | NULL | | BTREE | | |
| data | 1 | country_category_index | 1 | country | A | 498 | NULL | NULL | | BTREE | | |
| data | 1 | country_category_index | 2 | category | A | 997 | NULL | NULL | YES | BTREE | | |
+-------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
4 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
因此 cookie_id 上有一个非唯一索引,而 Country+category 列上有一个非唯一索引。现在的情况是,每周我都应该运行查询
问题是,删除数据需要花费大量时间 - 这就是我在国家+类别列上设置索引的原因。但是,“DELETE”语句仍然不使用索引,而是尝试扫描整个表:
mysql> EXPLAIN DELETE FROM data WHERE country='Y' and category='X';
+----+-------------+-------+------------+------+------------------------+------+---------+------+----------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+------------------------+------+---------+------+----------+----------+-------------+
| 1 | DELETE | data | NULL | ALL | country_category_index | NULL | NULL | NULL | 24767570 | 100.00 | Using where |
+----+-------------+-------+------------+------+------------------------+------+---------+------+----------+----------+-------------+
Run Code Online (Sandbox Code Playgroud)
选择效果很好:
mysql> EXPLAIN SELECT id, cookie_id FROM data WHERE country='Y' and category='X';
+----+-------------+-------+------------+------+------------------------+------------------------+---------+-------------+----------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+------------------------+------------------------+---------+-------------+----------+----------+-------+
| 1 | SIMPLE | data | NULL | ref | country_category_index | country_category_index | 365 | const,const | 10130630 | 100.00 | NULL |
+----+-------------+-------+------------+------+------------------------+------------------------+---------+-------------+----------+----------+-------+
Run Code Online (Sandbox Code Playgroud)
有什么办法可以优化 DELETE 查询吗?
通过首先删除数据,您实际上使数据无法访问。您不想避免这种“停机时间”吗?
考虑将替换数据加载到临时表中,然后执行 IODKU 来更新主数据:
INSERT INTO main (...)
ON DUPLICATE KEY UPDATE
col1 = VALUES(col1),
...
SELECT ... FROM temp;
Run Code Online (Sandbox Code Playgroud)
是否可以删除行;IODKU 不会提供该功能。但是,您可以在它之前加上类似的内容
ALTER TABLE temp ADD INDEX (...); -- to speed up the LEFT JOIN below
DELETE FROM main
USING main
LEFT JOIN temp ON ...
WHERE temp... IS NULL;
Run Code Online (Sandbox Code Playgroud)