我正在使用Grails框架进行项目,该项目使用Hibernate进行ORM。 Grails支持命名查询,这些查询转换为休眠标准。我一直在使用P6Spy和SQLProfiler来尝试提高其中一个命名查询的性能。
问题是,当我运行没有order by子句的查询时,它运行大约.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
如果有任何专家阅读,这里是文章域名的精简版:
static hasMany = [articleFeeds: ArticleFeed]
Date updated
static namedQueries = {
containedInFeeds { feedList ->
articleFeeds{
or{
feedList.each{ feed ->
eq("feed", feed)
}
}
}
}
}
Grails Note 我通过添加
尝试了这两点orderBy("updated", "desc")
maxResults("50")
在域中,并尝试
Article.containedInFeeds().listDistinct(max: 50, sort: "updated", order: "desc")
在控制器中,但生成的SQL似乎都是相同的。
我已尝试在更新字段的文章表中添加索引,但这不会导致性能提升。
文章表约有190,000个项目。
我还对查询进行了解释(作为我发现建议的博客文章),并注意到没有订单,只有“使用位置”被列为附加内容。当使用“使用Where,使用临时,使用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 | |
+----+-------------+-----------+--------+---------------------------------------+--------------------+---------+----------------------------+-------+----------------------------------------------+
感谢您的帮助。
答案 0 :(得分:1)
是的,当然。您需要创建索引。 尝试在feed_articles.feed_id(第一个)和article.id,article.updated(第二个)上创建复合索引。