Increasing query performance on joins and using order by
I am using the Grails framework for a project, which uses Hibernate for ORM. Grails supports named queries, which translate to hibernate criteria. I've been using P6Spy and SQLProfiler to try to increase performance of one of these named queries.
The issue is that when I run the query with no order by clause, it runs in about .1200 seconds. When I add the order by clause, it increases to 15 seconds.
Here's (roughly) what the end result query looks like:
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
l开发者_高级运维imit
50
In case there are any grails experts reading, here's a stripped down version of the article domain:
static hasMany = [articleFeeds: ArticleFeed]
Date updated
static namedQueries = {
containedInFeeds { feedList ->
articleFeeds{
or{
feedList.each{ feed ->
eq("feed", feed)
}
}
}
}
}
Grails Note I've tried this both by adding
orderBy("updated", "desc")
maxResults("50")
in the domain, and by trying
Article.containedInFeeds().listDistinct(max: 50, sort: "updated", order: "desc")
in the controller, but the resulting SQL seems to be identical either way.
I've tried adding an index to the article table for the updated field, but that lead to no performance improvements.
The article table has roughly 190,000 items.
I also ran an explain on the queries (as a blog post I came across suggested), and noticed that without the order by, only "Using Where" is listed as extras. When using the ordered by "Using Where, Using Temporary, Using Filesort" are all listed.
I'm guessing that I have not created an index properly, that the mysql instance needs some tuning done, or both.
Edit
More information
I've been searching the web for more information on indexing, especially on when joins and order by's are used. The closest write-up I've been able to find is this: http://hackmysql.com/case5 but the site says it's not longer maintained, and I'm guessing those techniques are obsolete (they didn't work for me at least). I'd really like to gain an understanding of how/why things should be indexed, and not simply be given the answer.
Here are the requested table definitions and explain output.
Article Table
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 table_
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;
Explain Output
I did slightly modify the query, by changing the where clause to pull from 10 feed_id's:
feed_articles.feed_id = 1 or
.
.
.
feed_articles.feed_id = 10
Output:
+----+-------------+-----------+--------+---------------------------------------+--------------------+---------+----------------------------+-------+----------------------------------------------+
| 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 | |
+----+-------------+-----------+--------+---------------------------------------+--------------------+---------+----------------------------+-------+----------------------------------------------+
Thanks for the help so far.
Yes, of course. You need to create indexes. Try to create on feed_articles.feed_id (first) and a composite index on article.id, article.updated (second).
精彩评论