mysql8的select count(*) 反而慢了
本帖最后由 马天艺 于 2023-7-20 10:18 编辑mysql8的select count(*) 反而慢了,之前字符集是utf8mb3更换为utf8mb4 也是一样的
Table: scanrecord
Create Table: CREATE TABLE `scanrecord` (
`SCANRECORD_ID` varchar(20) CHARACTER SET utf8mb3 NOT NULL,
`SN` varchar(150) CHARACTER SET utf8mb3 NOT NULL,
`PRODUCTTYPE` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`MODEL` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`CREATETIME` datetime NOT NULL,
`LASTUPDATE` datetime NOT NULL,
`QUANTITY` int DEFAULT '1',
`CUSTOMER_ID` varchar(20) CHARACTER SET utf8mb3 NOT NULL,
`OUTERMODEL` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`STATUS` int DEFAULT '1',
`MSG` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`destination_country` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`integral_open` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`integral_role_id` varchar(20) CHARACTER SET utf8mb3 DEFAULT '' COMMENT '绉垎瑙勫垯琛↖D',
`retry_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`retry_date` datetime DEFAULT NULL COMMENT 'Retry鏃堕棿',
`user_id` varchar(20) CHARACTER SET utf8mb3 DEFAULT '' COMMENT '鐢ㄦ埛ID',
`code` int DEFAULT '1' COMMENT '鎵爜缁撴灉鐘舵€?1:鎴愬姛',
`sale_region_name` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`sn_data` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`transactionas_last_date` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`transactionas_date` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`integral_rule_id` bigint DEFAULT NULL COMMENT '绉垎瑙勫垯琛↖D',
`integral_rule_scancode_id` bigint DEFAULT NULL COMMENT '鎵爜绉垎瑙勫垯琛↖D',
`integral` int DEFAULT NULL COMMENT '绉垎鏁?,
`dup_scan` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`bus_country_code` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`promotion_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`present_integral` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`activity_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`language_field` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
PRIMARY KEY (`SCANRECORD_ID`),
KEY `CUSTOMER_ID` (`CUSTOMER_ID`),
KEY `scanrecord_ibfk_2` (`user_id`),
KEY `integral_role_id` (`integral_role_id`),
KEY `CREATETIME` (`CREATETIME`) USING BTREE,
KEY `idx_SN` (`SN`,`STATUS`),
KEY `idx_scanrecord_sn` (`SN`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
#mysql8.0 上的执行
root@mysqldb 22:19:> select count(*) from scanrecord;
+----------+
| count(*) |
+----------+
| 27093343 |
+----------+
1 row in set (33.46 sec)
root@mysqldb 22:21:>
root@mysqldb 22:21:> select count(*) from scanrecord;
+----------+
| count(*) |
+----------+
| 27093343 |
+----------+
1 row in set (33.49 sec)
root@mysqldb 22:22:> explain format=json select count(*) from scanrecord;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "3293518.66"
},
"table": {
"table_name": "scanrecord",
"access_type": "index",
"key": "CREATETIME",
"used_key_parts": [
"CREATETIME"
],
"key_length": "5",
"rows_examined_per_scan": 23081395,
"rows_produced_per_join": 23081395,
"filtered": "100.00",
"using_index": true,
"cost_info": {
"read_cost": "985379.16",
"eval_cost": "2308139.50",
"prefix_cost": "3293518.66",
"data_read_per_join": "560G"
}
}
}
} |
1 row in set, 1 warning (0.00 sec)
root@mysqldb 22:22:> select @@version
-> ;
+-----------+
| @@version |
+-----------+
| 8.0.34 |
+-----------+
1 row in set (0.00 sec)
root@mysqldb 22:23:>
#####mysql5.7上的执行
mysql> select count(*) from scanrecord;
+----------+
| count(*) |
+----------+
| 27270612 |
+----------+
1 row in set (10.41 sec)
mysql> select count(*) from scanrecord;
+----------+
| count(*) |
+----------+
| 27270626 |
+----------+
1 row in set (3.75 sec)
mysql> explain format=json select count(*) from scanrecord;
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "4314379.40"
},
"table": {
"table_name": "scanrecord",
"access_type": "index",
"key": "CREATETIME",
"used_key_parts": [
"CREATETIME"
],
"key_length": "5",
"rows_examined_per_scan": 17408057,
"rows_produced_per_join": 17408055,
"filtered": "100.00",
"using_index": true,
"cost_info": {
"read_cost": "832768.00",
"eval_cost": "3481611.19",
"prefix_cost": "4314379.40",
"data_read_per_join": "320G"
}
}
}
} |
1 row in set, 1 warning (0.00 sec)
mysql> select @@version;
+------------+
| @@version|
+------------+
| 5.7.25-log |
+------------+
1 row in set (0.00 sec)
几个问题补充
1. 是否完全相同运行环境
2. innodb_buffer_pool_size设置多大,以及其他几个buffer size
3. explain analyze执行计划贴出来 yejr 发表于 2023-7-20 13:37
几个问题补充
1. 是否完全相同运行环境
2. innodb_buffer_pool_size设置多大,以及其他几个buffer size
mysql5.7 的是虚拟机,mysql8 的是物理机
####mysql5.7
mysql>select count(*) from scanrecord;
+----------+
| count(*) |
+----------+
| 27507736 |
+----------+
1 row in set (11.43 sec)
mysql>show variables like 'innodb_buffer_pool_size';
+-------------------------+------------+
| Variable_name | Value |
+-------------------------+------------+
| innodb_buffer_pool_size | 1073741824 |
+-------------------------+------------+
1 row in set (0.09 sec)
mysql> explain select count(*) from scanrecord;
+----+-------------+------------+------------+-------+---------------+------------+---------+------+----------+----------+-------------+
| id | select_type | table | partitions | type| possible_keys | key | key_len | ref| rows | filtered | Extra |
+----+-------------+------------+------------+-------+---------------+------------+---------+------+----------+----------+-------------+
|1 | SIMPLE | scanrecord | NULL | index | NULL | CREATETIME | 5 | NULL | 17466894 | 100.00 | Using index |
+----+-------------+------------+------------+-------+---------------+------------+---------+------+----------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> select @@version;
+------------+
| @@version|
+------------+
| 5.7.25-log |
+------------+
1 row in set (0.00 sec)
####mysql8
root@mysqldb 15:08:> explain analyze select count(*) from scanrecord;
+-------------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------------+
| -> Count rows in scanrecord(actual time=32421..32421 rows=1 loops=1)
|
+-------------------------------------------------------------------------+
1 row in set (32.42 sec)
root@mysqldb 15:13:> show variables like 'innodb_buffer_pool_size';
+-------------------------+------------+
| Variable_name | Value |
+-------------------------+------------+
| innodb_buffer_pool_size | 6442450944 |
+-------------------------+------------+
1 row in set (0.00 sec)
root@mysqldb 15:15:> select @@version;
+-----------+
| @@version |
+-----------+
| 8.0.34 |
+-----------+
1 row in set (0.00 sec)
root@mysqldb 15:15:> select count(*) from scanrecord;
+----------+
| count(*) |
+----------+
| 27093343 |
+----------+
1 row in set (31.46 sec) 马天艺 发表于 2023-7-26 15:20
mysql5.7 的是虚拟机,mysql8 的是物理机
####mysql5.7
mysql>select count(*) from scanrecord;
8.0场景下,运行下面SQL看执行计划
explain select count(*) from scanrecord; yejr 发表于 2023-7-26 22:08
8.0场景下,运行下面SQL看执行计划
explain select count(*) from scanrecord;
explain select count(*) from scanrecord;
+----+-------------+------------+------------+-------+---------------+------------+---------+------+----------+----------+-------------+
| id | select_type | table | partitions | type| possible_keys | key | key_len | ref| rows | filtered | Extra |
+----+-------------+------------+------------+-------+---------------+------------+---------+------+----------+----------+-------------+
|1 | SIMPLE | scanrecord | NULL | index | NULL | CREATETIME | 5 | NULL | 23081395 | 100.00 | Using index |
+----+-------------+------------+------------+-------+---------------+------------+---------+------+----------+----------+-------------+
1 row in set, 1 warning (0.00 sec) 马天艺 发表于 2023-7-27 10:08
explain select count(*) from scanrecord;
+----+-------------+------------+------------+-------+-- ...
执行计划看起来一样的。
5.7的ibp比8.0的还要低,select速度反倒更快的确不太合理。
你可以试试多次select看下耗时,第一次肯定比较慢,也看看之后的耗时是多久。
另外,也要检查运行环境是否受到其他因素影响,例如同时还有其他高负载进程在跑,或者底层物理I/O设备性能不同等等。 这是一个bug。https://bugs.mysql.com/bug.php?id=111969 fander 发表于 2023-8-4 17:56
这是一个bug。https://bugs.mysql.com/bug.php?id=111969
验证器确认了,在8.0下的全表count(*)确实有问题
解决办法:
启用GreatSQL的并行查询 force_parallel_execute = ON
修改where条件为查询辅助索引,如下面的例子:
# 根据辅助索引列查询更高效
greatsql> show global status like 'innodb%data%read%';
+---------------------------+-------------+
| Variable_name | Value |
+---------------------------+-------------+
| Innodb_data_pending_reads | 0 |
| Innodb_data_read | 17106242560 |
| Innodb_data_reads | 1043933 |
+---------------------------+-------------+
3 rows in set (0.00 sec)
greatsql> select count(*) from sbtest12 where k>=0;
+----------+
| count(*) |
+----------+
| 12500000 |
+----------+
1 row in set (1.30 sec)
greatsql> show global status like 'innodb%data%read%';
+---------------------------+-------------+
| Variable_name | Value |
+---------------------------+-------------+
| Innodb_data_pending_reads | 0 |
| Innodb_data_read | 17358130176 |
| Innodb_data_reads | 1059314 |
+---------------------------+-------------+
# 查看执行计划
greatsql> explain select count(*) from sbtest4 where k>=0;
+----+-------------+-----------+------------+-------+---------------+------+---------+------+---------+----------+-------------------------------+
| id | select_type | table | partitions | type| possible_keys | key| key_len | ref| rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+------+---------+------+---------+----------+-------------------------------+
|1 | SIMPLE | <gather2> | NULL | ALL | NULL | NULL | NULL | NULL | 6165144 | 100.00 | Parallel execute (23 workers) |
|2 | SIMPLE | sbtest4 | NULL | range | k_4 | k_4| 4 | NULL | 6165144 | 100.00 | Using where; Using index |
+----+-------------+-----------+------------+-------+---------------+------+---------+------+---------+----------+-------------------------------+
# 根据主键列查询会全表扫描
greatsql> show global status like 'innodb%data%read%';
+---------------------------+-------------+
| Variable_name | Value |
+---------------------------+-------------+
| Innodb_data_pending_reads | 0 |
| Innodb_data_read | 17358130176 |
| Innodb_data_reads | 1059314 |
+---------------------------+-------------+
3 rows in set (0.00 sec)
greatsql> select count(*) from sbtest20 where id>=0;
+----------+
| count(*) |
+----------+
| 12500000 |
+----------+
1 row in set (3.88 sec)
greatsql> show global status like 'innodb%data%read%';
+---------------------------+-------------+
| Variable_name | Value |
+---------------------------+-------------+
| Innodb_data_pending_reads | 0 |
| Innodb_data_read | 20162317312 |
| Innodb_data_reads | 1230142 |
+---------------------------+-------------+
页:
[1]