优化 MySQL MEMORY 表的 DELETE 查询

Dav*_*ger 5 mysql delete memory btree

我运行一个大型论坛,该论坛维护用于后端数据存储的 MySQL 数据库。“会话”表跟踪登录的用户和来宾。目前大约有 10 万条记录,所以不是那么大。但是,当我们修剪旧记录时,这个会话表会出现在慢查询日志中:

# Time: 120719 10:05:11
# User@Host: xxx[xxx] @  [10.x.x.x]
# Thread_id: 369051896  Schema: forumdb  Last_errno: 0  Killed: 0
# Query_time: 8.352811  Lock_time: 0.000028  Rows_sent: 0  Rows_examined: 19635  Rows_affected: 19635  Rows_read: 0
# Bytes_sent: 13  Tmp_tables: 0  Tmp_disk_tables: 0  Tmp_table_sizes: 0
SET timestamp=1342710311;
DELETE FROM session
    WHERE lastactivity < 1342709401;
Run Code Online (Sandbox Code Playgroud)

我已经确认 lastactivity 表上有一个 BTREE 索引:

mysql> SHOW INDEX FROM session FROM forumdb;
+---------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table   | Non_unique | Key_name     | Seq_in_index | Column_name  | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| session |          0 | PRIMARY      |            1 | sessionhash  | NULL      |       78941 |     NULL | NULL   |      | HASH       |         |               |
| session |          1 | userid       |            1 | userid       | NULL      |       26313 |     NULL | NULL   |      | HASH       |         |               |
| session |          1 | idhash       |            1 | idhash       | NULL      |        8771 |     NULL | NULL   |      | HASH       |         |               |
| session |          1 | userid_2     |            1 | userid       | NULL      |        NULL |     NULL | NULL   |      | HASH       |         |               |
| session |          1 | userid_2     |            2 | lastactivity | NULL      |       39470 |     NULL | NULL   |      | HASH       |         |               |
| session |          1 | userid_3     |            1 | userid       | NULL      |        NULL |     NULL | NULL   |      | HASH       |         |               |
| session |          1 | userid_3     |            2 | host         | NULL      |       39470 |     NULL | NULL   |      | HASH       |         |               |
| session |          1 | lastactivity |            1 | lastactivity | A         |        NULL |     NULL | NULL   |      | BTREE      |         |               |
+---------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
8 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

我很好奇为什么删除查询需要这么长时间的记录。

应该注意的是,该表被大量使用,同时有这么多用户在线。我们有一些沉重的硬件坐在它后面。

关于我可以做些什么来加快这个过程的任何想法?它似乎正在锁定表,因此在执行此删除功能时,我会看到集群中的高负载。

查询缓存已关闭(我们使用 memcache)。这是 my.cnf 的相关部分:

table_open_cache=8242
table_definition_cache=600
open_files_limit=65535
binlog_cache_size=6M
sort_buffer_size=8M
key_buffer_size=5G
myisam_sort_buffer_size=256M
join_buffer_size=3M
thread_cache_size=1000
thread_concurrency=16
ft_min_word_len=3
tmp_table_size=512M
max_allowed_packet=128M
max_heap_table_size=512M
read_rnd_buffer_size=1M
skip-external-locking

query_cache_limit=1M
query_cache_size= 32M
query_cache_type = 0
Run Code Online (Sandbox Code Playgroud)

最后,这里有一些关于表的更多信息:

表信息

固定的:

将表更改为 InnoDB 后(下图中的 17:15),我看到性能要好得多,并且该表的慢日志中不再有 DELETE。自从进行此更改后,整个集群的性能都得到了提高。谢谢你。

CPU 结果

Der*_*ney 5

我可能会将您的 Memory 表转换为 InnoDB

ALTER TABLE session ENGINE=InnoDB
Run Code Online (Sandbox Code Playgroud)

对于你的情况。内存表适用于低写入、多次读取,如果丢失数据(例如加载配置值),您并不在意。但是当你开始写很多东西时,如果你有很多连接访问它,表锁就会杀死你:

尽管内存中处理 MEMORY 表,但它们不一定比繁忙服务器上的 InnoDB 表快,用于通用查询,或在读/写工作负载下。特别是,执行更新所涉及的表锁定会减慢来自多个会话的 MEMORY 表的并发使用。[源代码]

由于不关心数据丢失,跟踪会话数据似乎是一个不错的选择,但我认为在这种情况下,通过切换到 InnoDB,您可能会获得删除表锁的显着好处。