我有一个查询,要花很长时间才能执行。 表说明。这些表非常大,因此将在说明中提供相关的列。所有列都是varchar。
表1-常规
PK-CLAIM_ID
记录数-2.63毫米,表2-报名
记录数-250万
列-CLAIM_ID(PK),POLICY_ID,MEMBER_ID表3-成员
没有记录-2800万
列-MEMBER_ID(PK),POLICY_GROUP_ID表4-政策
没有记录-200万
Cols- POLICY_ID,policy_sub_general_type_id表5-余额
没有记录-1200万。
列
查询是
SELECT cg.CLAIM_ID,mem.Policy_group_ID ,
CAST(CASE when pol.policy_sub_general_type_id = 'PFL'
then (bal2.sum_insured - bal2.utilised_sum_insured)
when pol.policy_sub_general_type_id = 'PNF'
then (bal1.sum_insured - bal1.utilised_sum_insured)
end AS DECIMAL(10, 2) ) Balance_SI
FROM General cg
LEFT JOIN Enrol ce ON cg.CLAIM_ID = ce.CLAIM_ID
LEFT JOIN Member mem ON ce.MEMBER_ID = mem.MEMBER_ID
LEFT JOIN Policy pol ON pol.POLICY_ID = ce.POLICY_ID
LEFT join Balance bal1 ON bal1.MEMBER_ID = ce.MEMBER_ID
and bal1.MEMBER_ID is not null
LEFT join Balance bal2 ON bal2.Policy_group_ID = mem.Policy_group_ID
and bal2.Policy_group_ID is not null
GROUP BY cg.CLAIM_ID
说明说明显示
Select Type|table|Type|key|rows|Extra
_____________________________________
SIMPLE|cg |index|PRIMARY|2662233|Using Index
SIMPLE|ce |ref|index1|1|NULL
SIMPLE|mem|eq_ref|PRIMARY|1|using where
SIMPLE|pol|eq_ref|PRIMARY|1| Using Where
SIMPLE|bal1|ref|index2|3|Using Where
SIMPLE|bal2|ref|index1|1|using where
服务器参数
InnoDB_Buffer_pool-10GB
InnoDB_Log_File_Size-3GB
4核处理器
所有表和列都具有相同的排序规则和字符集,因此这不是排序规则问题。连接列也为varchar。 Explain语句显示(我认为)表已正确索引。 查询大约需要15分钟才能返回前50000行,这在当前时间是不可接受的。对于整个表来说,它仍在运行最后3个小时而没有任何结果。 不知道为什么会这样。请帮忙。
答案 0 :(得分:0)
对于初学者,您可以完全删除“ cg”别名“常规”表,除非用于其他未在此处显示的列。原因是,您直接从注册表中获得了索赔ID。只是删除额外的级别。
接下来,您的“分组依据”仅在声明中,但策略组ID属于您的选择。您是否也打算按照每个策略进行汇总?一个索赔可以涵盖多个保单组吗?如果不是,而您只是想将其延续下去,则可以通过 MAX(mem.Policy_Group_ID)作为Policy_Group_ID
正如Strawberry所指出的那样,按可能具有笛卡尔结果的位置进行聚合/分组可能会给您错误的答案。
我还建议您编辑帖子并确认一些其他详细信息,例如“余额表”。您对“ PNF”有一个基于“ PFL”的总数,我们知道它们的具体含义,但对我们没有任何意义。您的案例/何时从别名“ Bal1”与“ Bal2”中提取值。这是否是特定策略组未输入到余额表中而属于某个“通用存储桶”或特定于单个策略的存储桶的条件?例如定期覆盖“ X”,但是您对“ Y”类别有限制?
下面的内容更清楚了SQL的可读性,删除了常规表。
SELECT
ce.CLAIM_ID,
mem.Policy_group_ID,
CAST(CASE when pol.policy_sub_general_type_id = 'PFL'
then (bal2.sum_insured - bal2.utilised_sum_insured)
when pol.policy_sub_general_type_id = 'PNF'
then (bal1.sum_insured - bal1.utilised_sum_insured) end AS DECIMAL(10,2)) Balance_SI
FROM
Enrol ce
LEFT JOIN Member mem
on ce.MEMBER_ID = mem.MEMBER_ID
LEFT join Balance bal2
on mem.Policy_group_ID = bal2.Policy_group_ID
and bal2.Policy_group_ID <> ''
LEFT JOIN Policy pol
on ce.POLICY_ID = pol.POLICY_ID
LEFT join Balance bal1
on ce.MEMBER_ID = bal1.MEMBER_ID
and bal1.MEMBER_ID <> ''
GROUP BY
ce.CLAIM_ID
最后,查看您的案子/何时加入Bal2别名,您没有引用成员ID,所以让我们向您展示您可能遇到的笛卡尔杀手。例如,联邦雇员属于一个政策组,拥有2万名雇员。现在,您有一个注册记录与资产负债表相连?是每个策略组一个记录还是每个成员/策略组一个记录。如果按成员/策略,则每次尝试从Bal2获取价值时,您都在浏览20k余额记录。而余额表的“ Bal1”别名对每个成员ID都是显式的。所以我知道这两个字段都在表中,这可能会杀死您。
同样,请编辑您现有的帖子以澄清详细信息和关系,尤其是1:1 vs 1:n
答案 1 :(得分:0)
这还不是答案
我不清楚您的数据库架构。
我有很多问题和想法,如何加快查询速度。
让我们看一下查询的第一部分:
SELECT cg.CLAIM_ID,
mem.Policy_group_ID,
CAST(
CASE
when
pol.policy_sub_general_type_id = 'PFL' then
(bal2.sum_insured - bal2.utilised_sum_insured)
when pol.policy_sub_general_type_id = 'PNF' then
(bal1.sum_insured - bal1.utilised_sum_insured)
END
AS DECIMAL(10,2)
) Balance_SI
您有“内联”函数调用,它们会影响性能:CAST, CASE, bal1.sum_insured - bal1.utilised_sum_insured, bal2.sum_insured - bal2.utilised_sum_insured
如果您的应用程序或您所做的任何事情都可以接受未返回“格式化”结果的查询,我建议删除CAST
-它会加快查询速度,而不会影响返回的实际值。您可以稍后在应用程序级别将这些值取整。
接下来是CASE
,同样,如果您具有应用级别(我希望),则可以返回原始数据而不是转换后的结果。我的意思是您可以返回3列:pol.policy_sub_general_type_id, bal1.sum_insured - bal1.utilised_sum_insured, bal2.sum_insured - bal2.utilised_sum_insured
而不是CASE
。但是我怀疑您甚至不需要这种优化。稍后再显示。
我也对您的JOIN
有很多疑问。但是,由于您尚未回答DRapp答案,所以我会保留一段时间。
让我们直接去查询,我怀疑会返回几乎相同的数据,如果有任何特殊问题,稍后再讨论细节。
SELECT
cg.CLAIM_ID,
mem.Policy_group_ID ,
SUM(bal.sum_insured - bal.utilised_sum_insured) Balance_SI
FROM `General` cg
LEFT JOIN Enrol ce
ON cg.CLAIM_ID = ce.CLAIM_ID
LEFT JOIN Member mem
ON ce.MEMBER_ID = mem.MEMBER_ID
LEFT JOIN Policy pol
ON pol.POLICY_ID = ce.POLICY_ID
AND (pol.policy_sub_general_type_id = 'PNF'
OR pol.policy_sub_general_type_id = 'PFL')
LEFT JOIN Balance bal
ON (bal.MEMBER_ID = ce.MEMBER_ID
AND bal.MEMBER_ID <> '')
OR (bal.Policy_group_ID = mem.Policy_group_ID
AND bal.Policy_group_ID <> '')
GROUP BY cg.CLAIM_ID, mem.Policy_group_ID