优化查询Indexing, EXPLAINMysql

问题描述

根据另一位开发人员在 stackoverflow 上的建议,我更新了我的查询如下,但我仍然需要进一步优化它。有人可以指导我如何最好地将索引应用于查询

见下面的查询

SELECT a.id,a.user_unique_id,a.loan_location,a.ippis,a.tel_no,a.organisation,a.branch,a.loan_agree,a.loan_type,a.appr,a.sold,a.loan_status,a.top_up,a.current_loan,a.date_created,a.date_updated,c.loan_id,c.user_unique_id AS tu_user_unique_id,c.ippis AS tu_ippis,c.top_up_approved,c.loan_type AS tu_loan_type,c.dse,c.status,c.current_loan AS tu_current_loan,c.record_category,c.date_created AS tu_date_created,c.date_updated AS tu_date_updated 
FROM loan_applications_tbl a
LEFT JOIN topup_or_reapplication_tbl c
    ON a.ippis=c.ippis   
WHERE ((c.status IN ('pending','corrected','Rejected','Processing','Captured','Reviewed','top up') 
       AND MONTH(CURRENT_DATE) IN (MONTH(c.date_created),MONTH(c.date_updated) 
       AND YEAR(CURRENT_DATE) IN (YEAR(c.date_created),YEAR(c.date_updated)) 
       AND   c.current_loan='1' )) 
OR ( a.loan_status IN ('pending','top up')
     AND MONTH(CURRENT_DATE) IN (MONTH(a.date_created),MONTH(a.date_updated)) )
     AND YEAR(CURRENT_DATE) IN (YEAR(a.date_created),YEAR(a.date_updated)) 
     AND (a.current_loan='1' 
          OR (a.current_loan='0' 
              AND a.loan_status IN('Approved','Closed')))))

执行时间:53s

记录数:11000

使用MysqL EXPLAIN给出如下截图:(如何最大化可能的keys列中的信息

EXPLAIN gives the screenshot below: (How do I maximise the information in the possible_keys column)

我已更新以下附加信息:

我在 c 和 a 之间使用 OR 的原因如下:

  1. a 是具有 66 列的父表,如果 a 上的新条目具有匹配/现有的 ippis({{ {1}})a 中的某些列被新条目中的数据更新/覆盖,而条目中的剩余数据作为新行插入 ac 不是在表 ippis 中唯一)。这是为了保留所有后续贷款请求的历史记录,同时不为冗余留出空间

  2. 在检索记录时,我需要大 c 子句使我能够检查 ORa 表的每个贷款记录的所有实例,其中 c列与我的 WHERE 子句中的参数匹配。

  3. status,date and current_loan 中总是会有完整的记录,但 a 中不会总是有记录,除非有更多的贷款请求需要相同的唯一 ID。 c 包含“谁是帐户人,例如通过唯一 ID”,以及第一笔贷款的附加/补充状态详细信息,随后,在第一笔贷款之后,“c”将是附加/补充状态具有相同唯一 ID 的实际贷款申请的详细信息

  4. 如果 "A" 是在 3 月 12 日创建的,并且在 3 月 16 日创建了一个新的 "c" 记录。 "A" 记录也会得到最后更新的标记为 3 月 16 日的记录,因为它有一个孩子,而新的 a 记录有它自己创建和更新的时间戳。 c 记录的 Updated 字段将为空/空,直到进行更改或存在 a 记录,c 记录的 Updated 字段将为空/空,直到有一些更改制作成 c 条记录

我希望这是可以理解的

解决方法

我一直忘记这个术语,因为它对我来说很少出现,但无论如何,您的索引无法通过使用 MONTH() 和 YEAR() 进行优化,因为它们是基础数据上的函数。通过应用日期范围,他们可以。因此,您可以保留您的月/年,例如某些内容是在 2021 年 1 月创建并在 2021 年 3 月更新,但此外,添加 "and c.date_created >= current_date AND current_date <= c.date_updated",如果索引中包含创建日期(小于在这种情况下,对于更新日期很重要。 其他表也是如此。

此外,当您从“a”表向“c”表进行左连接时,然后应用 where,这几乎就像您试图强制连接但由于 OR 保持左连接。

我会将基于“c”的条件移动到左连接,然后只测试在那里找到的记录是否为 NULL。

虽然不清楚(我问时没有澄清),但我认为当创建新的“A”记录时,系统实际上可能会将创建日期放入创建日期和更新日期。如果是这种情况,那么我们只需要查询/关注当前活动的当前月份/年份的最后更新日期字段。这现在是 where 子句的主要要求——不管底层 OR 条件到“C”表。

此外,由于月() 和年() 不是sargeable(感谢Ollie),我正在做一个预查询以获取当月和下个月的开始,以便我可以构建一个>

WHERE > beginning of this month and LESS than beginning of next month

至于索引,我会开始更新到

loan_applications_tbl ( date_created,date_updated,loan_status,current_loan,ippis )
topup_or_reapplication_tbl ( ippis,status,date_created,date_updated )

要尝试的最终查询。

SELECT 
        a.id,a.user_unique_id,a.loan_location,a.ippis,a.tel_no,a.organisation,a.branch,a.loan_agree,a.loan_type,a.appr,a.sold,a.loan_status,a.top_up,a.current_loan,a.date_created,a.date_updated,c.loan_id,c.user_unique_id tu_user_unique_id,c.ippis tu_ippis,c.top_up_approved,c.loan_type tu_loan_type,c.dse,c.status,c.current_loan tu_current_loan,c.record_category,c.date_created tu_date_created,c.date_updated tu_date_updated 
    FROM 
        -- this creates inline mySQL variables I can use for the WHERE condition
        -- by doing comma after with no explicit join,it is a single row
        -- and thus no Cartesian result,just @variables available now
        ( select 
                -- first truncating any TIME portion by casting to DATE()
                @myToday := date(curdate()),@howFarBack := date_sub( @myToday,interval 6 month ),-- now subtract day of month -1 to get first of THIS month
                @beginOfMonth := date_sub( @myToday,interval dayOfMonth( @myToday ) -1 day ),-- and now,add 1 month for beginning of next
                @beginNextMonth := date_add( @beginOfMonth,interval 1 month ) ) SqlVars,loan_applications_tbl a
    
            LEFT JOIN topup_or_reapplication_tbl c
                ON  a.ippis = c.ippis   
                AND c.current_loan='1'
                AND c.status IN ('pending','corrected','Rejected','Processing','Captured','Reviewed','top up') 
                AND 
                (
                        (@beginOfMonth <= c.date_created 
                    AND c.date_created < @beginNextMonth)
        
                OR
                        (@beginOfMonth <= a.date_updated 
                    AND a.date_updated < @beginNextMonth )
                )

    WHERE
            -- forces only activity for the single month in question
            -- since the "a" table knows of any "updates" to the "C",-- its updated basis will keep overall restriction to any accounts

            -- updated within this month in question only
            -- testing specifically for created OR updated within the
            -- current month in question

        a.date_created >= @howFarBack
        AND
            (
                    (@beginOfMonth <= a.date_created 
                AND a.date_created < @beginNextMonth)
        
            OR
                    (@beginOfMonth <= a.date_updated 
                AND a.date_updated < @beginNextMonth )
            )
        
        -- and NOW we can easily apply the OR without requiring
        -- to run against the ENTIRE set of BOTH tables.
        AND (
                    c.ippis IS NOT NULL
                OR 
                    ( a.loan_status IN (  'pending','top up')
                    AND (   
                            a.current_loan = '1' 
                        OR  (   a.current_loan = '0' 
                            AND a.loan_status IN ('Approved','Closed')
                            )
                        )
                    )
            )

关闭对查询的评论

我修改了查询以及第一个表上的主索引,以包含(第一个位置)记录的创建日期。我还添加了一个额外的变量 @howFarBack 作为考虑贷款的最长回溯时间。我默认为 6 个月前。您是否需要考虑贷款超过 6 个月的给定帐户?还是“a”帐户记录的内容可以追溯到 10 年前并希望包括在内?我的印象是这是一个新的贷款申请添加日期。如果是这样,在批准、最终确定、取消之前允许回溯 6 个月,仍然会阻止过去几个月的数据。

在 WHERE 子句中,我为 CREATED_DATE >= @howFarBack 添加了显式添加。永远不可能创建子记录,更不用说在原始添加日期之前的任何时间更新了。这将仅强制当月活动或转发符合条件。

例如:在 4 月 28 日创建一笔贷款。因此,运行查询,月初是 4 月 1 日,但比 5 月 1 日少(这允许包含 4 月 30 日晚上 11:59:59)

现在,我们进入了 5 月,5 月 4 日完成了贷款变更。我们在新的一个月里,@howFarBack 仍然允许 2020 年 12 月之前的旧应用程序与整个应用程序表相比,这些应用程序可能符合我们所知道的可以追溯到 2005 年的整个表。您始终使用最新的数据,并且可以轻松地将 @howFarBack 更改为最大回溯时间。这应该有助于您的性能需求。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...