问题描述
如何测量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倍加速。