Pergunta

My SQL is

SELECT authors.*, COUNT(*) FROM authors
    INNER JOIN resources_authors ON authors.author_id=resources_authors.author_id
WHERE
    resource_id IN
        (SELECT resource_id FROM resources_authors WHERE author_id = '1313')
    AND authors.author_id != '1313'
 GROUP BY authors.author_id`

I have indexes on all the fields in the query, but I still get a Using temporary; Using Filesort.

id  select_type         table             type            possible_keys                         key      key_len   ref                rows   Extra
1   PRIMARY             authors           ALL             PRIMARY                               NULL        NULL   NULL               16025  Using where; Using temporary; Using filesort
1   PRIMARY             resources_authors ref             author_id                             author_id      4   authors.author_id      3  Using where
2   DEPENDENT SUBQUERY  resources_authors unique_subquery resource_id,author_id,resource_id_2   resource_id  156   func,const             1  Using index; Using where

How can I improve my query, or table structure, to speed this query up?

There's an SQL Fiddle here, if you'd like to experiment: http://sqlfiddle.com/#!2/96d57/2/0

Foi útil?

Solução

I would approach it a different way by doing a "PreQuery". Get a list of all authors who have have a common resource count to another author, but to NOT include the original author in the final list. Once those authors are determined, get their name/contact info and the total count of common resources, but not the SPECIFIC resources that were in common. That would be a slightly different query.

Now, the query. to help optimize the query, I would have two indexes on one on just the (author_id) another combination on (resource_id, author_id) which you already have.

Now to explain the inner query. Do that part on its own first and you can see the execution plan will utilize the index. The intent here, the query starts with the resource authors but only cares about one specific author (where clause) which will keep this result set very short. That is IMMEDIATELY joined to the resource authors table again, but ONLY based on the same RESOURCE and the author IS NOT the primary one (from the where clause) giving you only those OTHER authors. By adding a COUNT(), we are now identifying how many for each respective offer have common resources, grouped by author returning one entry per author. Finally take that "PreQuery" result set (all records already prequalified above), and join to the authors. Get details and count() and done.

SELECT 
      A.*,
      PreQuery.CommonResources
   from 
      ( SELECT 
              ra2.author_id,
              COUNT(*) as CommonResources
           FROM 
              resources_authors ra1
                 JOIN resources_authors ra2
                    ON ra1.resource_id = ra2.resource_id
                    AND NOT ra1.author_id = ra2.author_id
           WHERE 
              ra1.author_id = 1313 
           GROUP BY
              ra2.author_id ) PreQuery
      JOIN authors A
         ON PreQuery.author_id = A.author_id
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top