2014-04-04 66 views
0

我的SQL是我可以优化这个MySQL查询吗?

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` 

我在查询所有字段的索引,但我仍然获得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 

如何改进我的查询或表结构来加快查询速度?

这里有一个SQL小提琴,如果你想尝试:http://sqlfiddle.com/#!2/96d57/2/0

+0

我不认为'author_id!= 1313'可以有效地使用索引。 – Barmar

+0

@MKhalidJunaid - 这将无法正常工作,因为永远不会返回任何结果。 –

+0

为什么你会说ID必须是1313,然后说它不= 1313? ...基本上你说的是把它拉出来,资源授权者是1313,作者不是1313 –

回答

1

我会做一个“PreQuery”接近它以不同的方式。获取具有共同资源计数给所有其他作者的所有作者的列表,但不要将最初的作者包括在最终列表中。一旦确定了这些作者,就可以获得他们的姓名/联系信息和共同资源的总数,而不是共同的特定资源。这将是一个稍微不同的查询。

现在,查询。为了帮助优化查询,我将在 上有两个索引,其中只有(author_id) 上的另一个组合(resource_id,author_id) 您已有。

现在来解释内部查询。首先执行该部分,您可以看到执行计划将使用索引。这里的意图是,查询从资源作者开始,但只关心一个特定的作者(where子句),它将保持这个结果集非常短。这是即时加入到资源作者表,但只基于相同的资源和作者不是主要的(从where子句)给你只有其他作者。通过添加COUNT(),我们现在可以确定每个相应优惠有多少公共资源,由作者按照每个作者返回一个条目进行分组。最后采用该“PreQuery”结果集(所有记录已经在上面进行了预审),并加入到作者中。获取详细信息并计数()并完成。

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 
+0

这真是太棒了。根据我的实际数据,查询时间从0.55秒减少到0.01秒。我仍然开始关注查询,这对我尝试优化的其他查询有影响,但是如果我已经正确理解了你,关键的一步是确保我的WHERE子句使用主表中的字段,而不是连接表,从而删除表扫描。 –

+0

@MarkBarnes,是的,我从你的查询的BASELINE开始。一个作者的事情(或多个,如果你关心多个提议,使用IN(ID列表))。然后,通过在这些相同的资源上加入连接给其他人(包括原作者),但原始作者的NOT不会将它们留在最终集合之外。 – DRapp

+0

@MarkBanes,顺便说一句,如果你有其他疑问,把它们扔到这里,只是打我看看。 – DRapp