开发者

Increasing query performance on joins and using order by

开发者 https://www.devze.com 2023-02-12 19:17 出处:网络
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 increa

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).

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号