我使用的是 Ubuntu 服务器版本 20.04
配置为 16GB RAM 和 2GB 交换设施。
我的会话表中有 1910 万条记录:
+----------+-----------------+-----------------+
| count(*) | min(session_id) | max(session_id) |
+----------+-----------------+-----------------+
| 19168798 | 6 | 19170401 |
+----------+-----------------+-----------------+
这是我的询问:
SELECT appid, country, COUNT(DISTINCT(uuid)) as total
FROM sessions
WHERE appid = (appids)
AND created >= (createdFrom) AND created <= (createdTo)
GROUP BY country
ORDER BY total DESC;
我已经在我的 ID、uuid 和创建的列上建立了索引。 当我运行查询时,加载数据几乎需要 5 分钟。
这里,是我的mysqld.cnf文件内容
[mysqld]
#
# * Basic Settings
#
user = mysql
# pid-file = /var/run/mysqld/mysqld.pid
# socket = /var/run/mysqld/mysqld.sock
# port = 3306
# datadir = /var/lib/mysql
# If MySQL is running as a replication slave, this should be
# changed. Ref https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_tmpdir
# tmpdir = /tmp
#
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address = 127.0.0.1
mysqlx-bind-address = 127.0.0.1
#
# * Fine Tuning
#
key_buffer_size = 16M
# max_allowed_packet = 64M
# thread_stack = 256K
# thread_cache_size = -1
# This replaces the startup script and checks MyISAM tables if needed
# the first time they are touched
myisam-recover-options = BACKUP
# max_connections = 151
# table_open_cache = 4000
#
# * Logging and Replication
#
# Both location gets rotated by the cronjob.
#
# Log all queries
# Be aware that this log type is a performance killer.
# general_log_file = /var/log/mysql/query.log
# general_log = 1
#
# Error log - should be very few entries.
#
log_error = /var/log/mysql/error.log
#
# Here you can see queries with especially long duration
# slow_query_log = 1
# slow_query_log_file = /var/log/mysql/mysql-slow.log
# long_query_time = 2
# log-queries-not-using-indexes
#
# The following can be used as easy to replay backup logs or for replication.
# note: if you are setting up a replication slave, see README.Debian about
# other settings you may need to change.
# server-id = 1
# log_bin = /var/log/mysql/mysql-bin.log
# binlog_expire_logs_seconds = 2592000
max_binlog_size = 100M
# binlog_do_db = include_database_name
# binlog_ignore_db = include_database_name
DESCRIBE sessions;
的结果
+----------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+----------------+
| session_id | int | NO | PRI | NULL | auto_increment |
| uuid | varchar(60) | NO | MUL | NULL | |
| userid | int | YES | | NULL | |
| appid | int | NO | | NULL | |
| mau_count | int | YES | | 0 | |
| systemversion | varchar(256) | NO | | NULL | |
| os | varchar(256) | NO | | NULL | |
| language | varchar(256) | YES | | NULL | |
| country | varchar(256) | YES | | NULL | |
| appversion | varchar(256) | YES | | NULL | |
| phonename | varchar(256) | YES | | NULL | |
| devicemodel | varchar(256) | YES | | NULL | |
| city | varchar(256) | YES | | NULL | |
| state | varchar(256) | YES | | NULL | |
| latitude | varchar(256) | YES | | NULL | |
| longitude | varchar(256) | YES | | NULL | |
| startdatetime | datetime | YES | | NULL | |
| enddatetime | datetime | YES | | NULL | |
| duration | int | YES | | NULL | |
| phonecarrier | varchar(256) | YES | | NULL | |
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
| is_deleted | int | NO | | NULL | |
| created | date | YES | MUL | NULL | |
| api_version | varchar(50) | YES | | NULL | |
+----------------+--------------+------+-----+---------+----------------+
SHOW INDEXES FROM sessions;
的结果
+----------+------------+----------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+----------+------------+----------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| sessions | 0 | PRIMARY | 1 | session_id | A | 19169624 | NULL | NULL | | BTREE | | | YES | NULL |
| sessions | 0 | session_id | 1 | session_id | A | 19169624 | NULL | NULL | | BTREE | | | YES | NULL |
| sessions | 1 | sessionUuid | 1 | uuid | A | 2738517 | NULL | NULL | | BTREE | | | YES | NULL |
| sessions | 1 | sessionCreated | 1 | created | A | 5189 | NULL | NULL | YES | BTREE | | | YES | NULL |
| sessions | 1 | sessionCreated | 2 | applicationsid | A | 25939 | NULL | NULL | | BTREE | | | YES | NULL |
| sessions | 1 | sessionCreated | 3 | country | A | 259048 | NULL | NULL | YES | BTREE | | | YES | NULL |
| sessions | 1 | sessionCreated | 4 | language | A | 383392 | NULL | NULL | YES | BTREE | | | YES | NULL |
| sessions | 1 | sessionCreated | 5 | uuid | A | 4792406 | NULL | NULL | | BTREE | | | YES | NULL |
+----------+------------+----------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
请指导我如何使此查询加速以及我需要更改什么。
如果查询没有匹配的索引,19.1 M 条记录就相当多了。唯一可以使用的索引是
created
的索引,这取决于查询中使用的日期范围:
尝试创建与 WEHRE 子句和 GROUP BY 匹配的索引:
create index session_appid_created on sessions (appid, created, country)
甚至
create index session_appid_created on sessions (appid, created, country, uuid)