如何在MYSQL上优化/衡量UPSERT性能?

问题描述

如何测量MysqL“ UPSERT”性能?更具体地说,在插入/更新/替换之前获取有关隐式搜索的信息吗?

使用MysqL 8,其架构包含三个字段。两个是主键的一部分。 Table目前是innodb,但这不是硬性要求。

CREATE TABLE IF NOT EXISTS `test`.`recent`
( `uid` int NOT NULL,`gid` int NOT NULL,`last` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`uid`,`gid`),KEY `idx_last` (`last`) USING BTREE
) ENGINE=InnoDB;

+----------+----------+------+-----+-------------------+-------+
| Field    | Type     | Null | Key | Default           | Extra |
+----------+----------+------+-----+-------------------+-------+
| uid      | int(11)  | NO   | PRI | NULL              |       |
| gid      | int(11)  | NO   | PRI | NULL              |       |
| last     | datetime | NO   | MUL | CURRENT_TIMESTAMP |       |
+----------+----------+------+-----+-------------------+-------+

我打算使用插入值

INSERT INTO test.recent (uid,gid) VALUES (1,1) 
  ON DUPLICATE KEY UPDATE last=Now();

由于EXPLAIN不会显示隐式搜索,因此仅显示插入内容,因此我该如何确定该查询性能

MysqL> explain INSERT INTO test.recent (uid,1) ON DUPLICATE KEY UPDATE last=Now();
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | INSERT      | recent | NULL       | ALL  | NULL          | NULL | NULL    | NULL | NULL |     NULL | NULL  |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set (0.00 sec)

MysqL> explain INSERT INTO test.recent (uid,1);
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | INSERT      | recent | NULL       | ALL  | NULL          | NULL | NULL    | NULL | NULL |     NULL | NULL  |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set (0.00 sec)

与实际搜索中的说明不同:

MysqL> explain select last from test.recent where uid=1 and gid=1;
+----+-------------+--------+------------+-------+---------------+---------+---------+-------------+------+----------+-------+
| id | select_type | table  | partitions | type  | possible_keys | key     | key_len | ref         | rows | filtered | Extra |
+----+-------------+--------+------------+-------+---------------+---------+---------+-------------+------+----------+-------+
|  1 | SIMPLE      | recent | NULL       | const | PRIMARY       | PRIMARY | 8       | const,const |    1 |   100.00 | NULL  |
+----+-------------+--------+------------+-------+---------------+---------+---------+-------------+------+----------+-------+
1 row in set,1 warning (0.00 sec)

我要弄清楚的变量之一是,如果我改为使用盲目更新,性能是否会完全改变:

MysqL> explain REPLACE INTO test.recent VALUES (1,1,Now());
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | REPLACE     | recent | NULL       | ALL  | NULL          | NULL | NULL    | NULL | NULL |     NULL | NULL  |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set (0.01 sec)

但是您可以看到,我获得的信息与“解释性插入”获得的信息相同(无用)。

我要根据测量结果回答的另一个问题是,情况会好还是坏(以及变坏多少),如果我使用DATE字段测试了两种增补方法(重复还是替换)(而不是DATETIME),从理论上讲,这将减少写入次数(但隐式搜索次数仍然相同)。但是再次说明,这里没有帮助。

解决方法

不要信任EXPLAIN,行数很少。

您的IODKU是最佳的。运作方式如下:

1-。像SELECT一样,向下钻取PRIMARY KEY BTree来找到具有(1,1)或应该有(1,1)的间距的行。这样可以尽可能快地进行查找。
2a。如果该行存在,请UPDATE
2b。如果该行不存在,请INSERT(并将last设置为“ CURRENT_TIMESTAMP”的DEFAULT)。

如果需要,我可以详细介绍这些步骤。但是我们每个都在亚毫秒级。

如果我想为查询计时,我会使用一些高分辨率计时器。时机很有可能会反弹,具体取决于是否有微风拂过,还是蝴蝶拍打着翅膀,还是月亮的相位。

注意事项:如果您“简化”对此问题的查询,则可能没有为 real 查询提供正确的信息。

如果您要处理一千个IODKU,那么可能会有涉及它们的优化。有一些典型的优化可以轻松实现10倍加速。