【问题标题】:How to optimise this sql query (inner joins)如何优化这个 sql 查询(内连接)
【发布时间】:2015-10-06 17:03:32
【问题描述】:

有没有办法优化这个查询。执行时间超过 40 秒。我尝试了很多方法,比如创建索引。效果不大。仍然查询时间太长。

 SELECT b.id,
   Count(DISTINCT a.id, c.chapters_id) AS pct,
   Count(DISTINCT e.id)                 AS eCount,
   Count(DISTINCT f.id)                 AS fCount,
   Count(DISTINCT d2.id)                 AS d2Count,
   b.NAME,
   e.NAME,
   e.address2,
   f.NAME,
   d2.is_active
FROM   tableA a
       INNER JOIN tableB b
               ON a.modules_id = b.id
       INNER JOIN tableC c
               ON a.modules_id = c.modules_id
       INNER JOIN tableD d1
               ON d1.id = b.store_users_id 
       INNER JOIN tableD d2
               ON d2.id = a.store_users_id
       INNER JOIN tableE e
               ON e.id = d2.stores_id
       INNER JOIN tableF f
               ON e.city = f.id
WHERE  b.type IN( 1, 2, 4 )
       AND b.organizations_id = 156
       AND b.is_enable = true
GROUP  BY b.NAME,b.id

解释

   +----+-------------+-------+--------+-----------------------------------------------------------------------------------------------------+-----------------------------+---------+--------------------------+------+---------------------------------------+
| id | select_type | table | type   | possible_keys                                                                                       | key                         | key_len | ref                      | rows | Extra                                 |
+----+-------------+-------+--------+-----------------------------------------------------------------------------------------------------+-----------------------------+---------+--------------------------+------+---------------------------------------+
|  1 | SIMPLE      | b     | range  | PRIMARY,fk_modules_organizations1,fk_modules_store_users1,sort_modules_name,wh_modules_type,new_idx | new_idx                     | 9       | NULL                     |  160 | Using index condition; Using filesort |
|  1 | SIMPLE      | c     | ref    | fk_module_chapters_modules1                                                                         | fk_module_chapters_modules1 | 4       |         b.id             |    1 | NULL                                  |
|  1 | SIMPLE      | d1    | eq_ref | PRIMARY                                                                                             | PRIMARY                     | 4       |         b.store_users_id |    1 | Using index                           |
|  1 | SIMPLE      | a     | ref    | store_users_id_UNIQUE,fk_user_modules_store_users1,fk_user_modules_modules1                         | fk_user_modules_modules1    | 4       |         b.id             |  149 | NULL                                  |
|  1 | SIMPLE      | d2    | eq_ref | PRIMARY,fk_store_users_stores1                                                                      | PRIMARY                     | 4       |         a.store_users_id |    1 | NULL                                  |
|  1 | SIMPLE      | e     | eq_ref | PRIMARY,Stores-Cities                                                                               | PRIMARY                     | 4       |        d2.stores_id      |    1 | Using where                           |
|  1 | SIMPLE      | f     | eq_ref | PRIMARY                                                                                             | PRIMARY                     | 4       |         e.city           |    1 | NULL                                  |
+----+-------------+-------+--------+-----------------------------------------------------------------------------------------------------+-----------------------------+---------+--------------------------+------+---------------------------------------+

【问题讨论】:

  • 请为您的表提供SHOW CREATE TABLE tablename 语句。这将帮助我们识别任何不正确的数据类型并查看您拥有的索引。此外,IN 总是只有 3 个值,还是会有所不同?这些价值观从何而来? (即用户输入,或以前运行的查询等)
  • 您好,感谢您查看我的查询。 IN 总是只有 3 个值 (1,2,4)。 5 个表的 SHOW CREATE TABLE 详细信息太大了。请告诉我您是否需要为任何特定表显示创建表。谢谢
  • 您没有收到任何回复,因为您没有提供明确的信息。提供所有 SHOW CREATE TABLE 语句,除非您的雇主或类似情况禁止您这样做,否则请更正您的查询以显示实际的表和列名称,而不是这些假名称。它有助于我们理解并降低您在编辑名称时出错的风险。无论如何,我们可以从 *_id 列和 EXPLAIN 语句中的键推断出大部分名称。

标签: mysql optimization query-optimization


【解决方案1】:

这可能会有所帮助:

INDEX(organizations_id, is_enable, type) -- on b

既然你说COUNT(DISTINCT...),闻起来就像JOINs 正在爆炸的行数,那么你DISTINCTifying 他们回到了它们应该在的位置。看到这一点的一种方法是在没有最终 GROUP BY 的情况下执行 SELECT COUNT(*) FROM ... JOIN ...。如果这个数字比任何表大小都大得多,那么您就有了这个经典问题。

有时解决方案是将JOIN 替换为

SELECT  ...,
        ( SELECT COUNT(*) FROM x ... )  AS x_ct,  -- instead of `JOIN x`
        ... 

【讨论】:

    猜你喜欢
    • 2012-03-16
    • 1970-01-01
    • 1970-01-01
    • 2015-03-18
    • 2013-05-27
    • 1970-01-01
    • 1970-01-01
    • 2019-09-03
    • 2012-09-22
    相关资源
    最近更新 更多