【问题标题】:mysql derived tables, performance, alternativemysql派生表,性能,替代
【发布时间】:2012-04-23 03:23:22
【问题描述】:

我有以下表格,

  1. link_books_genres,*表结构 -> book_id,genre_id*
  2. genres,*表结构 ->genre_id,genre_name*

给定一组 book_ids,我想形成以下结果,

result_set structure -> genre_id, genre_name, count(book_id).

我写了这个查询,

SELECT one.genre_id,
       one.genre_name, 
       two.count 
FROM   genres as one,(SELECT genre_id,
                   count(book_id) as count 
                   FROM link_f2_books_lists GROUP BY genre_id) as two 
WHERE  one.genre_id = two.genre_id;

我不知道这是否是最好的解决方案,但如果可能的话,我希望对其进行优化,或者它是否格式正确、经过验证。

附:它是用 ruby​​ on rails 完成的,所以任何面向 rails 的方法也可以。

【问题讨论】:

    标签: mysql ruby-on-rails join query-optimization derived-table


    【解决方案1】:

    您的查询未使用 SQL-92 JOIN 语法,而是使用较旧的隐式连接语法。是时候(20 年了),你应该开始使用它了。

    使用像COUNT 这样的关键字作为别名也不是很好。您可以改用cntbook_count

    SELECT one.genre_id,
           one.genre_name, 
           two.cnt 
    FROM   
           genres AS one
         INNER JOIN
           ( SELECT genre_id,
                    COUNT(book_id) AS cnt 
             FROM   link_f2_books_lists 
             GROUP BY genre_id
           ) AS two 
               ON one.genre_id = two.genre_id ;
    

    MySQL 通常使用COUNT(*) 会更快一些,所以如果book_id 不能是NULL,将COUNT(book_id) 更改为COUNT(*) 将是一个小的性能提升。


    当然,您可以在没有派生表的情况下重写 Join:

    SELECT one.genre_id,
           one.genre_name, 
           COUNT(*) AS cnt 
    FROM   
           genres AS one
         INNER JOIN
           link_f2_books_lists AS two 
               ON one.genre_id = two.genre_id 
    GROUP BY  one.genre_id ;
    

    在这两个版本中,您都可以将INNER JOIN 更改为LEFT OUTER JOIN,以便显示没有任何书籍的流派(0 个)。但是为了得到正确的结果,请使用COUNT(two.book_id) 而不是COUNT(*)

    上述版本(和您的版本)将不包含这些类型(这是使用 JOIN 语法的一个很好的理由,所需的更改非常简单。尝试使用您的 WHERE 版本!)


    LEFT JOIN 版本也可以这样写:

    SELECT one.genre_id,
           one.genre_name, 
           ( SELECT COUNT(*) 
             FROM   link_f2_books_lists AS two 
             WHERE  one.genre_id = two.genre_id 
           ) AS cnt 
    FROM   
           genres AS one ;
    

    关于性能,没有什么比测试自己更好的了。这一切都取决于您使用的 MySQL 版本(较新的版本将有更好的优化器,可以通过更多选项来选择创建执行计划,并且可能会将不同的版本识别为等效),表的大小,您拥有的索引,数据的分布(有多少不同的类型?平均每种类型有多少本书?等等),你的内存(和其他 MySQL)设置以及我现在可能忘记的许多其他因素。

    建议(genre_id, book_id) 上的索引在大多数情况下对所有版本都很有用。

    作为一般建议,在多对多表上同时拥有 (genre_id, book_id)(book_id, genre_id) 索引通常会很好。

    【讨论】:

    • 非常感谢。我将使用内部连接和计数(*)。我打算在我的数据库上安装 sphinxsearch。你怎么看?
    • 如果要全文搜索,是的,有多种产品可以和MySQL合作:Sphinx、Lucene、Solr。检查这个问题:Choosing a stand-alone full-text search server 或自己研究。
    • @beck03076:但这与问题无关。如果您有任何问题(对于数据库),太模糊而无法在 SO 上发布或寻求意见,您可以随时通过 DBA chat 找到某人
    • ypercube,非常感谢!
    【解决方案2】:
    SELECT one.genre_id, one.genre_name,  count(two.book_id) 
    FROM genres as one, link_books_genres as two 
    WHERE one.genre_id=two.genre_id
    GROUP BY genre_id
    

    【讨论】:

      猜你喜欢
      • 2017-04-30
      • 1970-01-01
      • 2017-09-09
      • 2011-01-20
      • 2010-09-23
      • 2012-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多