我有一个网站有一个活动的饲料,类似于像Facebook这样的社交网站有一个。这是一个“最新的第一个”列表,描述用户采取的行动。在制作中,该表中约有20万个条目。基于枚举的过滤器的平坦的MySQL表格出乎意料地很慢
因为这将是无论如何询问,我会先共享全表结构:
CREATE TABLE `karmalog` (
`id` int(11) NOT NULL auto_increment,
`guid` char(36) default NULL,
`user_id` int(11) default NULL,
`user_name` varchar(45) default NULL,
`user_avat_url` varchar(255) default NULL,
`user_sec_id` int(11) default NULL,
`user_sec_name` varchar(45) default NULL,
`user_sec_avat_url` varchar(255) default NULL,
`event` enum('EDIT_PROFILE','EDIT_AVATAR','EDIT_EMAIL','EDIT_PASSWORD','FAV_IMG_ADD','FAV_IMG_ADDED','FAV_IMG_REMOVE','FAV_IMG_REMOVED','FOLLOW','FOLLOWED','UNFOLLOW','UNFOLLOWED','COM_POSTED','COM_POST','COM_VOTE','COM_VOTED','IMG_VOTED','IMG_UPLOAD','LIST_CREATE','LIST_DELETE','LIST_ADMINDELETE','LIST_VOTE','LIST_VOTED','IMG_UPD','IMG_RESTORE','IMG_UPD_LIC','IMG_UPD_MOD','IMG_GEO','IMG_UPD_MODERATED','IMG_VOTE','IMG_VOTED','TAG_FAV_ADD','CLASS_DOWN','CLASS_UP','IMG_DELETE','IMG_ADMINDELETE','IMG_ADMINDELETEFAV','SET_PASSWORD','IMG_RESTORED','IMG_VIEW','FORUM_CREATE','FORUM_DELETE','FORUM_ADMINDELETE','FORUM_REPLY','FORUM_DELETEREPLY','FORUM_ADMINDELETEREPLY','FORUM_SUBSCRIBE','FORUM_UNSUBSCRIBE','TAG_INFO_EDITED','IMG_ADDSPECIE','IMG_REMOVESPECIE','SPECIE_ADDVIDEO','SPECIE_REMOVEVIDEO','EARN_MEDAL','JOIN') NOT NULL,
`event_type` enum('follow','tag','image','class','list','forum','specie','medal','user') NOT NULL,
`active` bit(1) NOT NULL,
`delete` bit(1) NOT NULL default '\0',
`object_id` int(11) default NULL,
`object_cache` text,
`object_sec_id` int(11) default NULL,
`object_sec_cache` text,
`karma_delta` int(11) NOT NULL,
`gold_delta` int(11) NOT NULL,
`newkarma` int(11) NOT NULL,
`newgold` int(11) NOT NULL,
`migrated` int(11) NOT NULL default '0',
`date_created` timestamp NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `user_sec_id` (`user_sec_id`),
KEY `image_id` (`object_id`),
KEY `date_event` (`date_created`,`event`),
KEY `event` (`event`),
KEY `date_created` (`date_created`),
CONSTRAINT `karmalog_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE SET NULL,
CONSTRAINT `karmalog_ibfk_2` FOREIGN KEY (`user_sec_id`) REFERENCES `user` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
优化这个表之前,我查询了5联接和我遇到了慢查询时间。我已经对所有这些数据进行了非规范化处理,以便不再有单个连接。所以表和查询是平坦的。
正如你在表的设计看,有一个“事件”字段,它是一个枚举,拿着几十个可能的值。在整个网站中,我展示了基于特定事件类型的活动供稿。通常,该查询看起来是这样的:
SELECT * FROM karmalog as k
WHERE k.event IN ($events) AND k.delete=0
ORDER BY k.date_created DESC, k.id DESC
LIMIT 0,30
什么这个查询的作用是找出在总集最新的30个条目匹配任何在$事件中传递的事件,它可以是多的是。
由于移除连接,并具有在大多数领域的指标,我期待这表现非常好,但事实并非如此。在200K条目上,它仍然需要3秒钟,我不明白为什么。
关于解决方案,我知道我可以存档旧条目或分区各事件类型的表,但将有相当代码的影响,我先想明白,为什么上面是这么慢。
作为临时解决,我现在这样做:
SELECT * FROM
(SELECT * FROM karmalog ORDER BY date_created DESC, id DESC LIMIT 0,1000) as karma
WHERE karma.event IN ($events) AND karma.delete=0
LIMIT $page,$pagesize
这样做是限制baseset中搜索到只有最新的1000个条目,希望和猜测,有30项找到我通过的过滤器。虽然它不是很强大。它不适用于更罕见的事件,并带来分页问题。
因此,我首先要得到的,为什么我的初始查询速度慢的根本原因,对我的期望。
编辑:我被要求分担执行计划。下面是测试查询:
EXPLAIN SELECT * FROM karmalog
WHERE event IN ('FAV_IMG_ADD','FOLLOW','COM_POST','IMG_VOTE','LIST_VOTE','JOIN','CLASS_UP','LIST_CREATE','FORUM_REPLY','FORUM_CREATE','FORUM_SUBSCRIBE','IMG_GEO','IMG_ADDSPECIE','SPECIE_ADDVIDEO','EARN_MEDAL') AND karmalog.delete=0
ORDER BY date_created DESC, id DESC
LIMIT 0,36
执行计划:
id = 1
select_type = SIMPLE
table = karmalog
type = range
possible_keys = event
key = event
key_len = 1
red = NULL
rows = 80519
Extra = Using where; Using filesort
我不知道如何读入上面的,但我知道,那种条款似乎真的杀了这个查询。通过这种分类,需要4.3秒,而不需要0.03秒。
EXPLAIN的后期输出以获得期望的查询 –
1 - 您正在使用的是什么MySQL版本? 2 - 提供选择查询的解释 –
您是否检查过实际执行计划? “in”子句可能会导致表扫描。您可能还需要考虑一种策略,在该策略中,您的主要搜索约束运行时有{id,event,date_created}一个表,并将您的karmalog表中的结果(id)加入。 – ErstwhileIII