【发布时间】:2011-02-20 18:11:35
【问题描述】:
我正在为一个项目使用 Grails 框架,该项目使用 Hibernate for ORM。 Grails 支持命名查询,它转换为休眠条件。我一直在使用 P6Spy 和 SQLProfiler 来尝试提高这些命名查询之一的性能。
问题是当我运行没有 order by 子句的查询时,它会在大约 0.1200 秒内运行。当我添加 order by 子句时,它增加到 15 秒。
这是(大致)最终结果查询的样子:
Select
*
from
article
left outer join
feed_articles
on
article.id = feed_articles.article_id
where
(
feed_articles.feed_id = 1 or
feed_articles.feed_id = 43 or
feed_articles.feed_id = 67
)
order by
article.updated
limit
50
如果有任何 grails 专家阅读,这里是文章域的精简版本:
static hasMany = [articleFeeds: ArticleFeed]
Date updated
static namedQueries = {
containedInFeeds { feedList ->
articleFeeds{
or{
feedList.each{ feed ->
eq("feed", feed)
}
}
}
}
}
Grails 笔记 我已经通过添加
orderBy("updated", "desc")
maxResults("50")
在域中,并通过尝试
Article.containedInFeeds().listDistinct(max: 50, sort: "updated", order: "desc")
在控制器中,但生成的 SQL 似乎是相同的。
我尝试为更新字段的文章表添加索引,但这并没有提高性能。
article 表大约有 190,000 项。
我还对查询进行了解释(作为我遇到的博客文章的建议),并注意到没有 order by,只有“Using Where”被列为额外内容。使用时按“Using Where、Using Temporary、Using Filesort”的顺序全部列出。
我猜我没有正确创建索引,mysql 实例需要进行一些调整,或两者兼而有之。
编辑
更多信息
我一直在网上搜索有关索引的更多信息,尤其是有关何时使用联接和排序依据的信息。我能找到的最接近的文章是这样的:http://hackmysql.com/case5 但该网站说它不再维护,我猜这些技术已经过时了(它们至少对我不起作用)。我真的很想了解应该如何/为什么要对事物进行索引,而不是简单地给出答案。
这里是请求的表定义和解释输出。
文章列表
CREATE TABLE `mydb`.`article` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`version` bigint(20) NOT NULL,
`link` varchar(255) DEFAULT NULL,
`image_id` bigint(20) DEFAULT NULL,
`unique_id` varchar(255) DEFAULT NULL,
`author` varchar(255) DEFAULT NULL,
`title` varchar(255) DEFAULT NULL,
`source` varchar(255) DEFAULT NULL,
`updated` datetime DEFAULT NULL,
`description` varchar(1000) DEFAULT NULL,
`date_created` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `FK317B135BE74D38` (`image_id`),
KEY `Updated_Idx_Test` (`id`,`updated`) USING BTREE,
CONSTRAINT `FK317B135BE74D38` FOREIGN KEY (`image_id`) REFERENCES `remote_image` (`id`)
)
ENGINE=InnoDB AUTO_INCREMENT=195939 DEFAULT CHARSET=latin1;
_Feed_Articles 表_
CREATE TABLE `mydb`.`feed_articles` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`version` bigint(20) NOT NULL,
`article_id` bigint(20) NOT NULL,
`feed_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
KEY `FK9E0121145D70E756` (`article_id`),
KEY `FK9E012114A51FD776` (`feed_id`),
CONSTRAINT `FK9E0121145D70E756` FOREIGN KEY (`article_id`) REFERENCES `article` (`id`),
CONSTRAINT `FK9E012114A51FD776` FOREIGN KEY (`feed_id`) REFERENCES `feed` (`id`)
)
ENGINE=InnoDB AUTO_INCREMENT=231684 DEFAULT CHARSET=latin1;
解释输出
我稍微修改了查询,将 where 子句更改为从 10 个 feed_id 中提取:
feed_articles.feed_id = 1 or
.
.
.
feed_articles.feed_id = 10
输出:
+----+-------------+-----------+--------+---------------------------------------+--------------------+---------+----------------------------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+--------+---------------------------------------+--------------------+---------+----------------------------+-------+----------------------------------------------+
| 1 | SIMPLE | feed_item | range | FK9E0121145D70E756,FK9E012114A51FD776 | FK9E012114A51FD776 | 8 | NULL | 51909 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | item | eq_ref | PRIMARY,Updated_Idx_Test | PRIMARY | 8 | wiumidev.feed_item.item_id | 1 | |
+----+-------------+-----------+--------+---------------------------------------+--------------------+---------+----------------------------+-------+----------------------------------------------+
感谢到目前为止的帮助。
【问题讨论】:
-
explain 还显示了它使用了哪些索引。您可以粘贴解释和模式的输出,这将有助于回答。
-
我发布的示例非常简略。今晚我将发布实际的查询/模式,希望能提供一些额外的信息。
-
另一个更新。我添加了以下键:feed_articles(feed_item, item_id) 现在解释使用索引显示 feed_item 表,但仍然有 using 临时,使用文件排序,这确实是我认为我需要消除的。