以下查询旨在接收用户的未读消息列表。它涉及 3 个表:recipients
包含用户与消息 ID 的关系,messages
包含消息本身,以及message_readers
包含哪些用户已阅读哪些消息的列表。
查询可靠地花费了 4.9 秒——这严重损害了我们的性能,尤其令人担忧,因为我们希望数据库最终会大几个数量级。诚然,它本质上是一个繁重的查询,但数据集很小,直觉上它似乎应该快得多。服务器有足够的内存(32gb),整个数据库应该一直加载到 RAM 中,并且盒子上没有其他东西在运行。
桌子都很小:
recipients: 23581
messages: 9679
message_readers: 2685
查询本身:
SELECT
m.*
FROM
messages m
INNER JOIN recipients r ON r.message_id = m.id
LEFT JOIN message_readers mr ON mr.message_id = m.id
WHERE
r.id = $user_id
AND (mr.read_by_id IS NULL OR mr.read_by_id <> $user_id)
解释计划非常简单:
+----+-------------+-------+--------+-----------------------------------+-----------------------------------+---------+--------------------------------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-----------------------------------+-----------------------------------+---------+--------------------------------+-------+-------------+
| 1 | SIMPLE | r | ref | index_recipients_on_id | index_recipients_on_id | 768 | const | 11908 | Using where |
| 1 | SIMPLE | m | eq_ref | PRIMARY | PRIMARY | 4 | db.r.message_id | 1 | Using index |
| 1 | SIMPLE | mr | ALL | NULL | NULL | NULL | NULL | 2498 | Using where |
+----+-------------+-------+--------+-----------------------------------+-----------------------------------+---------+--------------------------------+-------+-------------+
上有一个索引message_readers.read_by_id
,但我想它不能真正使用它,因为 IS NULL 条件。
我正在使用所有默认设置,但以下设置除外:
key_buffer=4G
query_cache_limit = 256M
query_cache_size = 1G
innodb_buffer_pool_size=12G
谢谢!