我有这个模式可以保存聊天消息。目前我有大约100k行,大约是5.5MB的数据。索引大小为6.5MB。当数据大小约为4MB时,索引大小约为3MB,因此以指数方式增长?
CREATE TABLE `messages` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`author` int(11) unsigned DEFAULT NULL,
`time` int(10) unsigned DEFAULT NULL,
`text` text,
`dest` int(11) unsigned DEFAULT NULL,
`type` tinyint(4) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `history` (`author`,`dest`,`id`) USING BTREE,
KEY `messages_ibfk_1` (`dest`),
FULLTEXT KEY `msg` (`text`),
CONSTRAINT `au` FOREIGN KEY (`author`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `messages_ibfk_1` FOREIGN KEY (`dest`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=105895 DEFAULT CHARSET=utf8;
我正在针对此表运行的主要查询以及我尝试优化它的时候是我需要显示2人之间聊天的分页历史记录
SELECT id, time, text, dest, type, author
FROM `messages`
WHERE (
(author = ? AND dest = ?) OR (author = ? AND dest = ?)
) AND id <= ? ORDER BY id DESC LIMIT ?, 25
历史记录的其他查询相同,只是它们具有针对搜索字词或日期范围的其他过滤器。
有什么办法可以减少索引大小并保持最佳性能吗?
答案 0 :(得分:1)
不要担心指数的增长。这可能是一个侥幸;当然不是&#34;指数&#34;。
假设主要问题是
的表现SELECT id, time, text, dest, type, author
FROM `messages`
WHERE (
(author = ? AND dest = ?) OR (author = ? AND dest = ?)
) AND id <= ? ORDER BY id DESC LIMIT ?, 25
我发现有三种技术可以显着提升:将OR
更改为UNION
,处理LIMIT
中的UNION
,并且不要使用OFFSET
分页。
( SELECT id, time, text, dest, type, author
FROM `messages`
WHERE author = ? -- one author & dest
AND dest = ?
AND id < ? -- where you "left off"
ORDER BY id DESC
LIMIT 25
) UNION ALL
( SELECT id, time, text, dest, type, author
FROM `messages`
WHERE author = ? -- the other author & dest
AND dest = ?
AND id < ? -- same as above
ORDER BY id DESC
LIMIT 25
)
ORDER BY id DESC
LIMIT 25; -- get the desired 25 from the 50 above
Pagination discussion解释了为什么应删除OFFSET
。它讨论了其他技术,包括使用26(在所有三个地方)而不是25,以便你知道这是否是最后一个&#39;页。
在第一次迭代中,AND id < ?
可以不用了。或者(更简单),你可以替换一个非常大的数字。
您的索引(author
,dest
,id
)是我制作的最佳选择。
当messages
越来越大和/或用户页面越过列表时,这个复杂的公式将会闪耀。