使用 group by 聚合计数 > 100 万用户 的 Mysql 查询性能变慢
Posted
技术标签:
【中文标题】使用 group by 聚合计数 > 100 万用户 的 Mysql 查询性能变慢【英文标题】:Mysql query performance slow using group by with aggregate count >1 million users 使用 group by 聚合计数 > 100 万用户 的 Mysql 查询性能变慢 【发布时间】:2015-12-17 06:25:59 【问题描述】:查询:
select count(*) as col_0_0_, usertb0_.ACCT_STATUS_ID as col_1_0_, usertb0_.user_type as col_2_0_
from user_tbl usertb0_
inner join
user_org_xref userorgxre1_
on usertb0_.USER_ID=userorgxre1_.USER_ID
where
(userorgxre1_.ORGANIZATION_ID in (2)) and (usertb0_.ACCT_STATUS_ID in (1 , 11 , 13 , 15 , 2))
group by usertb0_.ACCT_STATUS_ID , usertb0_.user_type;
表格和索引:
user_tbl ( PK: user_id) (Index: user_id, ACCT_STATUS_ID,covered index: ACCT_STATUS_ID,user_type)
user_org_xref (pk: user_org_id, FK: user_id) (index organization_id,user_id)
上面的查询需要 20 秒的时间来执行,任何人都可以帮助我提高性能
当平行命中更多时,它需要超过 30 秒。
查询说明:
【问题讨论】:
你能把解释的结果也贴一下吗? 有两件事让我印象深刻,您可能还有改进的余地:交换 where 子句中的条件,并使用 = 而不是 in() 来代替 organization_id 标准。 谢谢Shodow..我试过条件交换,但它没有改变 我们有多个组织可以输入这就是我使用“in”运算符的原因。查询统计 Ref img : i64.tinypic.com/drb8td.png 您是否尝试过删除count
聚合和group by
,以首先测试查询的一般性能,并将其与您现在正在执行的查询进行比较?这可能有助于找出查询的哪一部分需要注意。
【参考方案1】:
EXPLAIN 输出中的查询计划与图中的不同。 EXPLAIN 计划使用 user_tbl.cc_uid_sts_type 索引(大概在 ACCT_STATUS_ID 上)进行范围选择,从中检索 481k 行。然后它使用 USER_ID_FK_idx 索引加入 user_org_xref。如果这不包括 organization_id,那么添加它可以提高性能。
图表计划使用 ORG_ID_FK 索引(在 user_org_xref.organisation_id 上)检索 499k 行。然后它使用主键索引加入 user_tbl,从而将具有正确 ACCT_STATUS_ID 的组织用户过滤到 249k 行。
最终,无论您以哪种方式开始查询,都将不得不处理大量数据。给定组织中有近 50 万用户,并且具有正确 ACCT_STATUS_ID 的用户数量相似。因此,如果您确实需要提高性能,您可能需要以某种方式进行非规范化,例如将 ACCT_STATUS_ID 复制到 user_org_xref 表,尽管这显然是您最好避免的一种极端解决方案。
【讨论】:
【参考方案2】:我尝试了几种方法,实际上,最好的设置是在查询的每个表上强制使用一个索引。它在 4 秒内完成了这项工作......
这些是索引和最终查询:
CREATE INDEX <index_name_1> ON user_tbl (acct_status_id, user_type, user_id);
CREATE INDEX <index_name_2> ON user_org_xref (organization_id, user_id);
SELECT
COUNT(*) AS col_0_0_,
usertb0_.acct_status_id AS col_1_0_,
usertb0_.user_type AS col_2_0_
FROM user_tbl AS usertb0_ FORCE INDEX (<index_name_1>)
INNER JOIN user_org_xref AS userorgxre1_ FORCE INDEX (<index_name_2>) ON 1=1
AND userorgxre1_.user_id = usertb0_.user_id
WHERE 1=1
AND userorgxre1_.organization_id IN (2)
AND usertb0_.acct_status_id IN (1, 2, 11, 13, 15)
GROUP BY
usertb0_.acct_status_id,
usertb0_.user_type
;
【讨论】:
以上是关于使用 group by 聚合计数 > 100 万用户 的 Mysql 查询性能变慢的主要内容,如果未能解决你的问题,请参考以下文章
Oracle 用group by 去重计数还是用distinct 计数
可以单独对多个列进行 GROUP BY 并使用 django ORM 将它们中的每一列聚合到其他列?
sqlserver2008,sql编程,group by 用法