如何优化这个 sql 查询(内连接)
Posted
技术标签:
【中文标题】如何优化这个 sql 查询(内连接)【英文标题】:How to optimise this sql query (inner joins) 【发布时间】: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 语句中的键推断出大部分名称。
【参考方案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`
...
【讨论】:
以上是关于如何优化这个 sql 查询(内连接)的主要内容,如果未能解决你的问题,请参考以下文章
如何修复这个内连接 SQL 查询?而不是 1 count() 返回 3
如何将带有内连接语句的 Sql 查询转换为带有 Where 语句的 sql 查询(语句中没有内连接)