MySQL 许多 (~10-100K) 短 select 查询的性能下降
MySQL degrading performance over many (~10-100K) short select queries
我目前正在使用 MySQL 数据库在 Node 上构建一个应用程序,在初始 运行 时我必须计算大约 250M 项。每个计算需要 3 SELECT 个语句。
我现在正在测试数千个,以了解影响性能的因素。我看到奇怪的行为。最初的计算 运行 非常快,不到一秒就处理完 1k。然后,在几千(~20k)之后 运行 它减慢到每 1k 大约 4 秒。
现在,如果我让数据库单独放置一段时间(比如说 1 分钟),它会恢复速度以进行前 ~10k 次计算。
我实现了并发限制,同时计算不超过 20 个。增加限制似乎会降低性能。我还没有完全测试这个参数如何影响计算速度。
似乎有某种缓冲区填满了,即使之前的所有 SELECT 都应该完成。
其中每个计算 2000 行:
Just calculations: 2.557s
Just calculations: 1.566s
Just calculations: 1.617s
Just calculations: 1.543s
Just calculations: 1.475s
Just calculations: 1.635s
Just calculations: 1.613s
Just calculations: 3.324s
Just calculations: 4.103s
Just calculations: 8.325s
Just calculations: 7.583s
Just calculations: 7.482s
Just calculations: 7.216s
Just calculations: 7.145s
Just calculations: 7.419s
Just calculations: 7.244s
Just calculations: 7.066s
Just calculations: 7.635s
Just calculations: 7.169s
Just calculations: 7.194s
可以清楚地看到性能下降。降级也会影响 INSERT 查询,所以我很确定它特别是数据库层。
如有任何关于提高性能的提示或信息,我们将不胜感激。
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| item | CREATE TABLE `item` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`sku` varchar(255) NOT NULL,
`base_unit_of_measure` varchar(255) DEFAULT NULL,
`unit_price` double NOT NULL,
`blocked` tinyint(1) NOT NULL,
`item_disc__group` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `item_sku_unique` (`sku`)
) ENGINE=InnoDB AUTO_INCREMENT=1375125 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+---------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+---------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| contact | CREATE TABLE `contact` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`contact_id` varchar(255) NOT NULL,
`client_id` varchar(255) DEFAULT NULL,
`customer_disc__group` int DEFAULT NULL,
`customer_price_group` int DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `contact_contact_id_unique` (`contact_id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+---------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| sales_price | CREATE TABLE `sales_price` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`sku` varchar(255) NOT NULL,
`sales_type` int NOT NULL,
`sales_code` varchar(255) DEFAULT NULL,
`unit_of_measure_code` varchar(255) DEFAULT NULL,
`minimum_quantity` int NOT NULL,
`unit_price` double NOT NULL,
`allow_line_disc` tinyint(1) NOT NULL,
`starting_date` date DEFAULT NULL,
`ending_date` date DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `sales_price_unique` (`sku`,`sales_type`,`sales_code`,`starting_date`,`unit_of_measure_code`,`minimum_quantity`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+---------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+---------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| sales_line_discount | CREATE TABLE `sales_line_discount` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`type` int NOT NULL,
`code` varchar(255) NOT NULL,
`sales_type` int NOT NULL,
`sales_code` varchar(255) DEFAULT NULL,
`unit_of_measure_code` varchar(50) DEFAULT NULL,
`minimum_quantity` int NOT NULL,
`line_discount` double NOT NULL,
`starting_date` date DEFAULT NULL,
`ending_date` date DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `line_discount_unique` (`type`,`code`,`sales_type`,`sales_code`,`starting_date`,`unit_of_measure_code`,`minimum_quantity`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+---------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
针对这些表的 运行 查询如下:
bindings: [ 'TESTCONTACT1', 1 ],
SELECT `contact`.*
FROM `contact`
WHERE `contact`.`contact_id` = ?
LIMIT ?
bindings: [
0, 'DUMMYSKU24999',
1, 'DUMMYGROUP',
'2021-08-30', '2021-08-30',
0, 'TESTCONTACT1',
1, 2,
2, 3,
'TESTCAMP1', 'TESTCAMP2'
]
SELECT `sales_line_discount`.*
FROM `sales_line_discount`
WHERE ( ( `type` = ?
AND `code` = ?
OR ( `type` = ?
AND `code` = ? ) )
AND `starting_date` <= ?
AND `ending_date` >= ? )
AND ( `sales_type` = ?
AND `sales_code` = ?
OR ( `sales_type` = ?
AND `sales_code` = ? )
OR ( `sales_type` = ? )
OR ( `sales_type` = ?
AND `sales_code` IN ( ?, ? ) ) )
bindings: [
'DUMMYSKU24999', '2021-08-30',
'2021-08-30', 0,
'TESTCONTACT1', 1,
2, 2,
3, 'TESTCAMP1',
'TESTCAMP2'
],
SELECT `sales_price`.*
FROM `sales_price`
WHERE `sku` = ?
AND `starting_date` <= ?
AND `ending_date` >= ?
AND ( `sales_type` = ?
AND `sales_code` = ?
OR ( `sales_type` = ?
AND `sales_code` = ? )
OR ( `sales_type` = ? )
OR ( `sales_type` = ?
AND `sales_code` IN ( ?, ? ) ) )
最后的原因是后台进程周期性地占用应用的部分可用资源。
由于计算机一点也不落后,我曾假设它只使用一个内核并且在其他内核上工作不会影响它,但 htop 证明不同。杀死所有不必要的进程解决了性能问题。
我目前正在使用 MySQL 数据库在 Node 上构建一个应用程序,在初始 运行 时我必须计算大约 250M 项。每个计算需要 3 SELECT 个语句。 我现在正在测试数千个,以了解影响性能的因素。我看到奇怪的行为。最初的计算 运行 非常快,不到一秒就处理完 1k。然后,在几千(~20k)之后 运行 它减慢到每 1k 大约 4 秒。
现在,如果我让数据库单独放置一段时间(比如说 1 分钟),它会恢复速度以进行前 ~10k 次计算。
我实现了并发限制,同时计算不超过 20 个。增加限制似乎会降低性能。我还没有完全测试这个参数如何影响计算速度。 似乎有某种缓冲区填满了,即使之前的所有 SELECT 都应该完成。
其中每个计算 2000 行:
Just calculations: 2.557s
Just calculations: 1.566s
Just calculations: 1.617s
Just calculations: 1.543s
Just calculations: 1.475s
Just calculations: 1.635s
Just calculations: 1.613s
Just calculations: 3.324s
Just calculations: 4.103s
Just calculations: 8.325s
Just calculations: 7.583s
Just calculations: 7.482s
Just calculations: 7.216s
Just calculations: 7.145s
Just calculations: 7.419s
Just calculations: 7.244s
Just calculations: 7.066s
Just calculations: 7.635s
Just calculations: 7.169s
Just calculations: 7.194s
可以清楚地看到性能下降。降级也会影响 INSERT 查询,所以我很确定它特别是数据库层。
如有任何关于提高性能的提示或信息,我们将不胜感激。
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| item | CREATE TABLE `item` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`sku` varchar(255) NOT NULL,
`base_unit_of_measure` varchar(255) DEFAULT NULL,
`unit_price` double NOT NULL,
`blocked` tinyint(1) NOT NULL,
`item_disc__group` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `item_sku_unique` (`sku`)
) ENGINE=InnoDB AUTO_INCREMENT=1375125 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+---------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+---------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| contact | CREATE TABLE `contact` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`contact_id` varchar(255) NOT NULL,
`client_id` varchar(255) DEFAULT NULL,
`customer_disc__group` int DEFAULT NULL,
`customer_price_group` int DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `contact_contact_id_unique` (`contact_id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+---------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| sales_price | CREATE TABLE `sales_price` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`sku` varchar(255) NOT NULL,
`sales_type` int NOT NULL,
`sales_code` varchar(255) DEFAULT NULL,
`unit_of_measure_code` varchar(255) DEFAULT NULL,
`minimum_quantity` int NOT NULL,
`unit_price` double NOT NULL,
`allow_line_disc` tinyint(1) NOT NULL,
`starting_date` date DEFAULT NULL,
`ending_date` date DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `sales_price_unique` (`sku`,`sales_type`,`sales_code`,`starting_date`,`unit_of_measure_code`,`minimum_quantity`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+---------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+---------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| sales_line_discount | CREATE TABLE `sales_line_discount` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`type` int NOT NULL,
`code` varchar(255) NOT NULL,
`sales_type` int NOT NULL,
`sales_code` varchar(255) DEFAULT NULL,
`unit_of_measure_code` varchar(50) DEFAULT NULL,
`minimum_quantity` int NOT NULL,
`line_discount` double NOT NULL,
`starting_date` date DEFAULT NULL,
`ending_date` date DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `line_discount_unique` (`type`,`code`,`sales_type`,`sales_code`,`starting_date`,`unit_of_measure_code`,`minimum_quantity`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+---------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
针对这些表的 运行 查询如下:
bindings: [ 'TESTCONTACT1', 1 ],
SELECT `contact`.*
FROM `contact`
WHERE `contact`.`contact_id` = ?
LIMIT ?
bindings: [
0, 'DUMMYSKU24999',
1, 'DUMMYGROUP',
'2021-08-30', '2021-08-30',
0, 'TESTCONTACT1',
1, 2,
2, 3,
'TESTCAMP1', 'TESTCAMP2'
]
SELECT `sales_line_discount`.*
FROM `sales_line_discount`
WHERE ( ( `type` = ?
AND `code` = ?
OR ( `type` = ?
AND `code` = ? ) )
AND `starting_date` <= ?
AND `ending_date` >= ? )
AND ( `sales_type` = ?
AND `sales_code` = ?
OR ( `sales_type` = ?
AND `sales_code` = ? )
OR ( `sales_type` = ? )
OR ( `sales_type` = ?
AND `sales_code` IN ( ?, ? ) ) )
bindings: [
'DUMMYSKU24999', '2021-08-30',
'2021-08-30', 0,
'TESTCONTACT1', 1,
2, 2,
3, 'TESTCAMP1',
'TESTCAMP2'
],
SELECT `sales_price`.*
FROM `sales_price`
WHERE `sku` = ?
AND `starting_date` <= ?
AND `ending_date` >= ?
AND ( `sales_type` = ?
AND `sales_code` = ?
OR ( `sales_type` = ?
AND `sales_code` = ? )
OR ( `sales_type` = ? )
OR ( `sales_type` = ?
AND `sales_code` IN ( ?, ? ) ) )
最后的原因是后台进程周期性地占用应用的部分可用资源。
由于计算机一点也不落后,我曾假设它只使用一个内核并且在其他内核上工作不会影响它,但 htop 证明不同。杀死所有不必要的进程解决了性能问题。