MySQL 删除几条记录需要很多 (40) 秒,而相同数据的 SELECT 很快
MySQL DELETE takes many (40) seconds for few records while a SELECT of the same data is fast
任何人都可以解释为什么 DELETE 语句需要更多时间来执行吗?我们没有创建任何 TRIGGER 或 CASCADE。从 5.5 迁移到 8.0 时,我们开始注意到这个问题。是不是8.0调参的问题?
DELETE s FROM storefront s LEFT JOIN MASTER m ON m.userid=s.userid WHERE m.userid IS NULL
9 row(s) affected
Execution Time : 40.816 sec
Transfer Time : 0.001 sec
Total Time : 40.817 sec
同时,SELECT语句只需要几毫秒。
SELECT s.userid FROM storefront s LEFT JOIN MASTER m ON m.userid=s.userid WHERE m.userid IS NULL
Total Time : 0.05 sec
如有任何帮助,我们将不胜感激。我们有更好的服务器硬件,16 GB RAM。
这里是 DELETE 语句的 PROFILING 信息。
It is CPU_user(19.046875 seconds) and CPU_system(43.156250 seconds) taking most of the time out of the total execution time 50.24 seconds ....
这不是答案,但它可以帮助找出花费了这么多时间的地方。使用分析
SET PROFILING=ON;
**sample**
mysql> SET PROFILING=ON;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> select * from photons where photons >= 100;
+----+---------------------+---------+
| id | mytime | photons |
+----+---------------------+---------+
| 1 | 2020-02-26 12:00:00 | 100 |
| 3 | 2020-02-26 12:01:00 | 100 |
| 4 | 2020-02-26 12:05:00 | 200 |
+----+---------------------+---------+
3 rows in set (0.01 sec)
mysql> SHOW PROFILE ALL;
+----------------------+----------+----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+----------------------+-------------+
| Status | Duration | CPU_user | CPU_system | Context_voluntary | Context_involuntary | Block_ops_in | Block_ops_out | Messages_sent | Messages_received | Page_faults_major | Page_faults_minor | Swaps | Source_function | Source_file | Source_line |
+----------------------+----------+----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+----------------------+-------------+
| starting | 0.000130 | 0.000071 | 0.000057 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | NULL | NULL | NULL |
| checking permissions | 0.002022 | 0.000127 | 0.000103 | 2 | 0 | 160 | 0 | 0 | 0 | 2 | 1 | 0 | check_access | sql_authorization.cc | 802 |
| Opening tables | 0.000474 | 0.000040 | 0.000033 | 1 | 0 | 8 | 0 | 0 | 0 | 1 | 1 | 0 | open_tables | sql_base.cc | 5715 |
| init | 0.000043 | 0.000023 | 0.000020 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | handle_query | sql_select.cc | 121 |
| System lock | 0.000811 | 0.000046 | 0.000035 | 2 | 0 | 16 | 0 | 0 | 0 | 2 | 2 | 0 | mysql_lock_tables | lock.cc | 323 |
| optimizing | 0.000474 | 0.000027 | 0.000023 | 1 | 0 | 8 | 0 | 0 | 0 | 1 | 1 | 0 | optimize | sql_optimizer.cc | 151 |
| statistics | 0.000027 | 0.000014 | 0.000012 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | optimize | sql_optimizer.cc | 367 |
| preparing | 0.000763 | 0.000044 | 0.000036 | 2 | 0 | 16 | 0 | 0 | 0 | 2 | 2 | 0 | optimize | sql_optimizer.cc | 475 |
| executing | 0.000007 | 0.000003 | 0.000003 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | exec | sql_executor.cc | 119 |
| Sending data | 0.000103 | 0.000057 | 0.000046 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | exec | sql_executor.cc | 195 |
| end | 0.001408 | 0.000062 | 0.000050 | 1 | 0 | 248 | 0 | 0 | 0 | 1 | 0 | 0 | handle_query | sql_select.cc | 199 |
| query end | 0.000378 | 0.000029 | 0.000022 | 1 | 0 | 8 | 0 | 0 | 0 | 1 | 1 | 0 | mysql_execute_command | sql_parse.cc | 4946 |
| closing tables | 0.000409 | 0.000022 | 0.000020 | 1 | 0 | 8 | 0 | 0 | 0 | 1 | 1 | 0 | mysql_execute_command | sql_parse.cc | 4998 |
| freeing items | 0.000030 | 0.000017 | 0.000012 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | mysql_parse | sql_parse.cc | 5610 |
| cleaning up | 0.000026 | 0.000014 | 0.000012 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | dispatch_command | sql_parse.cc | 1924 |
+----------------------+----------+----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+----------------------+-------------+
15 rows in set, 1 warning (0.00 sec)
mysql>
关键词是"MyISAM"。 可能需要很长时间的原因有很多。
(我假设两个 table 都在 userid
上有一个索引?并且列定义相同?)
SELECT
会非常快,因为它只会使用索引来查找有问题的用户 ID。 0.05 秒几乎是 "too slow".
- MyISAM 将在
DELETE
期间执行 table 锁定。
- MyISAM 将每一行存储在 .MYD 文件中的某处。索引在 .MYI 文件中,即使对于主键也是如此。
- 我认为通过更改行的初始字节来删除行。 (实际上是一个字节,其唯一目的是表示已删除。
- 在 MyISAM 中,通常,一行是 .MYD 中的连续字节流。删除和一些更新将在 .MYD 中留下漏洞。
- 插入更喜欢先填补漏洞,如果失败则增加文件。请注意,大行将是片段的链接列表。这可能会导致越来越慢的全行选择。
- Oracle 计划摆脱 MyISAM。
这些并没有真正解释40秒只删除9行。
请提供 SHOW CREATE TABLE
和 EXPLAIN DELETE ...
;可能有您遗漏或我错误假设的细节。
底线:改用 InnoDB,这些问题就会消失。
任何人都可以解释为什么 DELETE 语句需要更多时间来执行吗?我们没有创建任何 TRIGGER 或 CASCADE。从 5.5 迁移到 8.0 时,我们开始注意到这个问题。是不是8.0调参的问题?
DELETE s FROM storefront s LEFT JOIN MASTER m ON m.userid=s.userid WHERE m.userid IS NULL
9 row(s) affected
Execution Time : 40.816 sec
Transfer Time : 0.001 sec
Total Time : 40.817 sec
同时,SELECT语句只需要几毫秒。
SELECT s.userid FROM storefront s LEFT JOIN MASTER m ON m.userid=s.userid WHERE m.userid IS NULL
Total Time : 0.05 sec
如有任何帮助,我们将不胜感激。我们有更好的服务器硬件,16 GB RAM。
这里是 DELETE 语句的 PROFILING 信息。
It is CPU_user(19.046875 seconds) and CPU_system(43.156250 seconds) taking most of the time out of the total execution time 50.24 seconds ....
这不是答案,但它可以帮助找出花费了这么多时间的地方。使用分析
SET PROFILING=ON;
**sample**
mysql> SET PROFILING=ON;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> select * from photons where photons >= 100;
+----+---------------------+---------+
| id | mytime | photons |
+----+---------------------+---------+
| 1 | 2020-02-26 12:00:00 | 100 |
| 3 | 2020-02-26 12:01:00 | 100 |
| 4 | 2020-02-26 12:05:00 | 200 |
+----+---------------------+---------+
3 rows in set (0.01 sec)
mysql> SHOW PROFILE ALL;
+----------------------+----------+----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+----------------------+-------------+
| Status | Duration | CPU_user | CPU_system | Context_voluntary | Context_involuntary | Block_ops_in | Block_ops_out | Messages_sent | Messages_received | Page_faults_major | Page_faults_minor | Swaps | Source_function | Source_file | Source_line |
+----------------------+----------+----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+----------------------+-------------+
| starting | 0.000130 | 0.000071 | 0.000057 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | NULL | NULL | NULL |
| checking permissions | 0.002022 | 0.000127 | 0.000103 | 2 | 0 | 160 | 0 | 0 | 0 | 2 | 1 | 0 | check_access | sql_authorization.cc | 802 |
| Opening tables | 0.000474 | 0.000040 | 0.000033 | 1 | 0 | 8 | 0 | 0 | 0 | 1 | 1 | 0 | open_tables | sql_base.cc | 5715 |
| init | 0.000043 | 0.000023 | 0.000020 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | handle_query | sql_select.cc | 121 |
| System lock | 0.000811 | 0.000046 | 0.000035 | 2 | 0 | 16 | 0 | 0 | 0 | 2 | 2 | 0 | mysql_lock_tables | lock.cc | 323 |
| optimizing | 0.000474 | 0.000027 | 0.000023 | 1 | 0 | 8 | 0 | 0 | 0 | 1 | 1 | 0 | optimize | sql_optimizer.cc | 151 |
| statistics | 0.000027 | 0.000014 | 0.000012 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | optimize | sql_optimizer.cc | 367 |
| preparing | 0.000763 | 0.000044 | 0.000036 | 2 | 0 | 16 | 0 | 0 | 0 | 2 | 2 | 0 | optimize | sql_optimizer.cc | 475 |
| executing | 0.000007 | 0.000003 | 0.000003 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | exec | sql_executor.cc | 119 |
| Sending data | 0.000103 | 0.000057 | 0.000046 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | exec | sql_executor.cc | 195 |
| end | 0.001408 | 0.000062 | 0.000050 | 1 | 0 | 248 | 0 | 0 | 0 | 1 | 0 | 0 | handle_query | sql_select.cc | 199 |
| query end | 0.000378 | 0.000029 | 0.000022 | 1 | 0 | 8 | 0 | 0 | 0 | 1 | 1 | 0 | mysql_execute_command | sql_parse.cc | 4946 |
| closing tables | 0.000409 | 0.000022 | 0.000020 | 1 | 0 | 8 | 0 | 0 | 0 | 1 | 1 | 0 | mysql_execute_command | sql_parse.cc | 4998 |
| freeing items | 0.000030 | 0.000017 | 0.000012 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | mysql_parse | sql_parse.cc | 5610 |
| cleaning up | 0.000026 | 0.000014 | 0.000012 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | dispatch_command | sql_parse.cc | 1924 |
+----------------------+----------+----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+----------------------+-------------+
15 rows in set, 1 warning (0.00 sec)
mysql>
关键词是"MyISAM"。 可能需要很长时间的原因有很多。
(我假设两个 table 都在 userid
上有一个索引?并且列定义相同?)
SELECT
会非常快,因为它只会使用索引来查找有问题的用户 ID。 0.05 秒几乎是 "too slow".- MyISAM 将在
DELETE
期间执行 table 锁定。 - MyISAM 将每一行存储在 .MYD 文件中的某处。索引在 .MYI 文件中,即使对于主键也是如此。
- 我认为通过更改行的初始字节来删除行。 (实际上是一个字节,其唯一目的是表示已删除。
- 在 MyISAM 中,通常,一行是 .MYD 中的连续字节流。删除和一些更新将在 .MYD 中留下漏洞。
- 插入更喜欢先填补漏洞,如果失败则增加文件。请注意,大行将是片段的链接列表。这可能会导致越来越慢的全行选择。
- Oracle 计划摆脱 MyISAM。
这些并没有真正解释40秒只删除9行。
请提供 SHOW CREATE TABLE
和 EXPLAIN DELETE ...
;可能有您遗漏或我错误假设的细节。
底线:改用 InnoDB,这些问题就会消失。