Mysql Join Query需要很长时间才能执行

时间:2018-08-06 12:08:57

标签: mysql sql indexing query-optimization

我有一个查询,要花很长时间才能执行。 表说明。这些表非常大,因此将在说明中提供相关的列。所有列都是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个小时而没有任何结果。 不知道为什么会这样。请帮忙。

2 个答案:

答案 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