MySQL
1. 環(huán)境準(zhǔn)備
- mysql 版本為 8.0.21。
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.21 |
+-----------+
- 創(chuàng)建用來(lái)測(cè)試表 demo。
drop table IF EXISTS demo;
CREATE TABLE demo (
id bigint NOT null AUTO_INCREMENT PRIMARY KEY,
value int
);
-- 插入 update 命令需要的數(shù)據(jù)
insert into demo(value) VALUES(0);
- 創(chuàng)建用來(lái)執(zhí)行
update語(yǔ)句的存儲(chǔ)過(guò)程。
DELIMITER $$
DROP PROCEDURE IF EXISTS update_demo;
CREATE PROCEDURE update_demo(IN count INTEGER)
BEGIN
declare var int;
set var=0;
while var<count do
UPDATE demo set value=value+1 where id=1;
set var=var+1;
end while;
END; $$
DELIMITER ;
執(zhí)行完上述命令后驗(yàn)證一下數(shù)據(jù)。
mysql> show create procedure update_demo;
+-------------+-----------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+
| Procedure | sql_mode | Create Procedure | character_set_client | collation_connection | Database Collation |
+-------------+-----------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+
| update_demo | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION | CREATE DEFINER=`root`@`localhost` PROCEDURE `update_demo`(IN count INTEGER)
BEGIN
declare var int;
set var=0;
while var<count do
UPDATE demo set value=value+1 where id=1;
set var=var+1;
end while;
END | latin1 | latin1_swedish_ci | utf8mb4_0900_ai_ci |
+-------------+-----------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+
1 row in set (0.00 sec)
mysql> show create table demo;
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| demo | CREATE TABLE `demo` (
`id` bigint NOT NULL AUTO_INCREMENT,
`value` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> select * from demo;
+----+-------+
| id | value |
+----+-------+
| 1 | 0 |
+----+-------+
1 row in set (0.00 sec)
2. tps 測(cè)試
調(diào)用存儲(chǔ)過(guò)程觸發(fā) update 執(zhí)行。
-- 執(zhí)行 20 次 update
mysql> call update_demo(20);
Query OK, 1 row affected (2.04 sec)
mysql> select * from demo;
+----+-------+
| id | value |
+----+-------+
| 1 | 20 |
+----+-------+
1 row in set (0.03 sec)
發(fā)現(xiàn)執(zhí)行 20 次 update,耗時(shí) 2s,單行 tps 為 10。
PostgreSQL
1. 環(huán)境準(zhǔn)備
- postgresql 版本為 12.4。
athena=> select version();
version
------------------------------------------------------------------------------------------------------------------
PostgreSQL 12.4 (Debian 12.4-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
(1 row)
-- 查詢自動(dòng)提交配置(發(fā)現(xiàn)默認(rèn)是關(guān)閉的)
athena=> \echo :AUTOCOMMIT
off
-- 設(shè)置為自動(dòng)提交模式
athena=> \set AUTOCOMMIT on
athena=> \echo :AUTOCOMMIT
on
- 創(chuàng)建用來(lái)測(cè)試表 demo。
drop table if exists demo;
-- 創(chuàng)建表之前要先提權(quán),切換為有權(quán)限的角色。
set role athena;
CREATE TABLE demo (
id bigserial NOT NULL PRIMARY KEY,
value int
);
-- 插入 update 命令需要的數(shù)據(jù)
insert into demo(id, value) VALUES(1, 0);
- 創(chuàng)建用來(lái)執(zhí)行
update語(yǔ)句的存儲(chǔ)過(guò)程。
create or replace procedure update_demo(count INTEGER)
language plpgsql
as $$
declare var integer;
begin
var := 0;
while var<count loop
UPDATE demo set value=value+1 where id=1;
var := var+1;
commit; --提交事務(wù)
insert into demo(value) VALUES(0);
rollback; -- 回滾事務(wù)
end loop;
end;
$$;
通過(guò) rollback 語(yǔ)句保證每個(gè) update 操作是獨(dú)立的事務(wù)。(如果不是獨(dú)立的事務(wù),rollback 語(yǔ)句會(huì)回滾 update 操作)。
執(zhí)行完上述命令后驗(yàn)證一下數(shù)據(jù)。
athena=> select proname,prosrc from pg_proc where proname ='update_demo';
proname | prosrc
-------------+----------------------------------------------
update_demo | +
| declare var integer; +
| begin +
| var := 0; +
| while var<count loop +
| UPDATE demo set value=value+1 where id=1;+
| var := var+1; +
| commit; --提交事務(wù) +
| insert into demo(value) VALUES(0); +
| rollback; -- 回滾事務(wù) +
| end loop; +
| end; +
|
(1 row)
athena=> \d demo
Table "public.demo"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+----------------------------------
id | bigint | | not null | nextval('demo_id_seq'::regclass)
value | integer | | |
Indexes:
"demo_pkey" PRIMARY KEY, btree (id)
athena=> select * from demo;
id | value
----+-------
1 | 0
(1 row)
Time: 0.618 ms
2. tps 測(cè)試
調(diào)用存儲(chǔ)過(guò)程觸發(fā) update 執(zhí)行。
-- 執(zhí)行 20 次 update
athena=> call update_demo(20);
CALL
Time: 8.376 ms
athena=> select * from demo;
id | value
----+-------
1 | 20
(1 row)
Time: 0.552 ms
-- 執(zhí)行 1000 次 update
athena=> call update_demo(1000);
CALL
Time: 338.440 ms
athena=> select * from demo;
id | value
----+-------
1 | 1020
(1 row)
Time: 0.575 ms
-- 執(zhí)行 3000 次 update
athena=> call update_demo(3000);
CALL
Time: 1137.671 ms (00:01.138)
athena=> select * from demo;
id | value
----+-------
1 | 4020
(1 row)
Time: 0.732 ms
發(fā)現(xiàn)執(zhí)行 3000 次 update,耗時(shí) 1s,單行 tps 為 3000。
MySQL 和 PostgreSQL 行鎖 tps 對(duì)比
- MySQL:單行
tps為 10 - PostgreSQL:單行
tps為 3000
后續(xù)
1. 咨詢大佬
首先咨詢了一波 cto,和 cto 的交流如下所示:
初醒 2020-8-19 16:07:21
shulin,請(qǐng)教一個(gè)技術(shù)問(wèn)題。
昨天聽(tīng)說(shuō)了mysql 行鎖tps 非常慢,只有10~20。
然后我今天測(cè)試對(duì)比了下 mysql 和 pg 的行鎖 tps,發(fā)現(xiàn)mysql只有10tps,pg有3000tps。
為什么 pg 的行鎖 tps 會(huì)這么高呢?
hot potato 2020-8-19 16:53:38
你這個(gè)mysql的數(shù)據(jù)是有些奇怪。我按照你的sql執(zhí)行了一下,耗時(shí)0.05秒,在SSD上。
對(duì)于這種簡(jiǎn)單語(yǔ)句的執(zhí)行,影響tps的應(yīng)該主要是commit時(shí)磁盤flush的速度。對(duì)于機(jī)械硬盤一般每秒一百多次。
TPS只有10我覺(jué)得怎么樣都不太應(yīng)該的。
初醒 16:55:03
我是用 docker 在 office-cluster-1 跑的mysql
初醒 16:55:34
自動(dòng)提交是開(kāi)啟的嗎?
shulin 16:58:25
開(kāi)啟的
mysql> show variables like '%autocommit%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
hot potato 2020-8-19 16:58:34
office-cluster-1上可能有其他程序干擾
hot potato 2020-8-19 16:58:49
另外office-cluster-1是一個(gè)老的pc,機(jī)械硬盤
初醒 16:59:15
難怪,可能是機(jī)械硬盤的問(wèn)題
初醒 16:59:32
您是在哪臺(tái)機(jī)器測(cè)試的呢?
初醒 17:00:02
我是昨天聽(tīng)一個(gè)在有贊支付平臺(tái)的學(xué)長(zhǎng)說(shuō)的,mysql 單行tps 只有20左右。今天就測(cè)試了
shulin 17:00:04
我是在自己的pc上跑的
初醒 17:00:15
哦哦
初醒 17:00:21
我也在本地裝一個(gè)mysql 試試

CTO 的測(cè)試結(jié)果
查看 Linux 磁盤是否是 SSD 盤
meikai@office-cluster-1:~$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 298.1G 0 disk
├─sda1 8:1 0 290.7G 0 part /
├─sda2 8:2 0 1K 0 part
└─sda5 8:5 0 7.4G 0 part [SWAP]
sr0 11:0 1 1024M 0 rom
# 返回 1:SATA盤
meikai@office-cluster-1:~$ cat /sys/block/sda/queue/rotational
1
2. 進(jìn)行驗(yàn)證
根據(jù) 怎么看自己的固態(tài)硬盤是哪個(gè)盤 得知,C 盤是ssd。
本地安裝 MySQL 到 C 盤,然后執(zhí)行之前的測(cè)試命令。
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.21 |
+-----------+
1 row in set (0.00 sec)
mysql> drop table IF EXISTS demo;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> CREATE TABLE demo (
-> id bigint NOT null AUTO_INCREMENT PRIMARY KEY,
-> value int
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> insert into demo(value) VALUES(0);
Query OK, 1 row affected (0.00 sec)
mysql> DELIMITER $$
mysql>
mysql> DROP PROCEDURE IF EXISTS update_demo;
-> CREATE PROCEDURE update_demo(IN count INTEGER)
-> BEGIN
-> declare var int;
-> set var=0;
-> while var<count do
-> UPDATE demo set value=value+1 where id=1;
-> set var=var+1;
-> end while;
-> END; $$
Query OK, 0 rows affected (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
mysql>
mysql> DELIMITER ;
mysql> select * from demo;
+----+-------+
| id | value |
+----+-------+
| 1 | 0 |
+----+-------+
1 row in set (0.00 sec)
mysql> show variables like '%autocommit%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set, 1 warning (0.00 sec)
mysql> call update_demo(20);
Query OK, 1 row affected (0.04 sec)
mysql> call update_demo(100);
Query OK, 1 row affected (0.19 sec)
mysql> call update_demo(500);
Query OK, 1 row affected (0.98 sec)
mysql> call update_demo(600);
Query OK, 1 row affected (1.34 sec)
mysql> call update_demo(500);
Query OK, 1 row affected (1.09 sec)
發(fā)現(xiàn)執(zhí)行 500 次 update,耗時(shí) 1s,單行 tps 為 500。
所以之前的測(cè)試結(jié)果【單行 tps 為 10】應(yīng)該是機(jī)器上其他程序干擾和機(jī)械硬盤導(dǎo)致的。
劃重點(diǎn)
- 對(duì)于這種簡(jiǎn)單語(yǔ)句的執(zhí)行,影響 tps 的應(yīng)該主要是
commit時(shí)磁盤 flush 的速度。 - 對(duì)于機(jī)械硬盤一般每秒一百多次。