如果您有很多类别,则无法提高此查询的效率。单个索引不能一次覆盖两个表MysqL
。
你所要做的非规范化:添加last_updated
,has_comments
并deleted
为article_categories
:
CREATE TABLE `article_categories` (
`article_id` int(11) NOT NULL DEFAULT '0',
`category_id` int(11) NOT NULL DEFAULT '0',
`last_updated` timestamp NOT NULL,
`has_comments` boolean NOT NULL,
`deleted` boolean NOT NULL,
PRIMARY KEY (`article_id`,`category_id`),
KEY `category_id` (`category_id`),
KEY `ix_articlecategories_category_comments_deleted_updated` (category_id, has_comments, deleted, last_updated)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
并运行以下查询:
SELECT *
FROM (
SELECT article_id
FROM article_categories
WHERE (category_id, has_comments, deleted) = (78, 1, 0)
ORDER BY
last_updated DESC
LIMIT 100, 20
) q
JOIN articles a
ON a.id = q.article_id
当然article_categories
,每当您更新中的相关列时,您也应该更新article
。这可以在触发器中完成。
请注意,该列has_comments
是布尔值:这将允许使用相等谓词对索引进行单个范围扫描。
还要注意,LIMIT
进入子查询。这将MysqL
使用默认情况下不使用的后行查找。请参阅我的博客中有关如何提高性能的文章:
如果您使用的是sql Server,则可以在查询上建立可索引的视图,从本质article_categories
上讲,它将使用服务器自动维护的带有附加字段的非规范化索引副本。