使用 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 查询性能变慢的主要内容,如果未能解决你的问题,请参考以下文章

通过 Group By Pandas 创建两个聚合列

Oracle 用group by 去重计数还是用distinct 计数

可以单独对多个列进行 GROUP BY 并使用 django ORM 将它们中的每一列聚合到其他列?

sqlserver2008,sql编程,group by 用法

sqlserver2008,sql编程,group by 用法

15group by子句与聚合函数