优化查询(索引、解释)Mysql
Optimise query (Indexing, EXPLAIN) Mysql
根据另一位开发人员在 Whosebug 上的建议,我已经更新了我的查询如下,但我仍然需要进一步优化它。有人可以指导我如何最好地将索引应用于查询。
参见下面的查询:
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', 'corrected', 'Rejected', 'Processing', 'Captured', 'Reviewed', '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 给出了以下屏幕截图:(如何最大化 possible_keys 列中的信息
我更新了以下附加信息:
出于以下原因,我在 c 和 a 之间使用 OR:
a
是具有 66 列的父级 table,如果 a
上的新条目具有 matching/existing ippis
(a
上的唯一字段)a
中的某些列 updated/overwriten 包含来自新条目的数据,而条目中的其余数据作为新行插入 c
(ippis
在 table c
中不是唯一的。这是为了保留所有后续贷款请求的历史记录,同时不留出冗余空间
在检索记录时,我需要大的 OR
子句来让我检查每个记录的所有实例的 a
和 c
table status, date and current_loan
列与我的 WHERE 子句中的参数匹配的贷款记录。
a
中始终会有完整的记录,但 c
中不会始终有记录,除非有更多贷款请求使用相同的唯一 ID。 a
包含 "who is the account person such as by unique ID", and the additional / supplemental status detail FOR THE FIRST LOAN, 随后,在第一笔贷款“c”之后将是附加/具有相同 Unique ID.
的实际贷款申请的补充状态详细信息
如果“A”是在 3 月 12 日创建的,并且在 3 月 16 日创建了一个新的“c”记录。“A”记录也获得最后更新的标记为 Mar 16 因为它有一个对它有一些影响的子附件,而新的 c
记录有它自己创建和更新的时间戳。 a
记录的更新字段将为 blank/null,直到进行更改或存在 c
记录,更新字段将为 c
记录的 blank/null直到对 c
记录
进行了一些更改
我希望这是可以理解的
我一直忘记这个术语,因为它很少出现在我身上,但是无论如何,您的索引不能通过使用 MONTH() 和 YEAR() 来优化,因为它们是基础数据的函数。通过应用日期范围,他们可以。因此,您可以保留 month/year,例如某些内容是在 2021 年 1 月创建并在 2021 年 3 月更新的,但此外,添加一个 "and c.date_created >= current_date AND current_date <= c.date_updated"
,如果其中包含创建日期,您可以使用该索引(在这种情况下,更新日期不太重要。
对于您的其他 table.
也是如此
此外,当您从“a”到“c”进行左连接时 table,然后应用 where,这几乎就像您试图强制连接但仍然是左连接由于 OR.
我会将基于“c”的条件移动到左连接,然后只测试在那里找到的记录是否为 NULL。
虽然不清楚(我问的时候没有弄清楚),但我认为当创建新的“A”记录时,系统实际上可能会将创建日期同时放入创建日期和更新日期。如果是这种情况,那么我们只需要 query/concern 最后更新的日期字段与 activity 的当前 month/year。现在这是 where 子句的主要要求——不管“C”的基础 OR 条件如何 table.
此外,由于 month() 和 year() 不是 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, current_loan, 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', 'corrected', 'Rejected', 'Processing',
'Captured', 'Reviewed', 'top up')
AND (
a.current_loan = '1'
OR ( a.current_loan = '0'
AND a.loan_status IN ('Approved', 'Closed')
)
)
)
)
关闭查询评论
我修改了查询以及第一个 table 上的主索引以包含(第一个位置)记录的创建日期。我还添加了一个额外的变量@howFarBack 作为考虑贷款的最长回溯时间。我默认为 6 个月前。您是否需要考虑将超过 6 个月的给定帐户用于贷款?还是“a”帐户记录了可以追溯到 10 年前并想要包含的内容?我的印象是这是一个新的 LOAN APPLICATION 添加日期。如果是这样,允许在批准、最终确定、取消之前回溯 6 个月,仍然会阻止历史上处理尽可能多的月数数据。
在 WHERE 子句中,我为 CREATED_DATE >= @howFarBack 添加了显式添加。永远不可能创建子记录,更不用说在原始添加日期之前的任何时间进行更新了。这将强制只有当月 activity 或 FORWARD 符合资格。
例如:在 4 月 28 日创建贷款。所以 运行 查询,月初是 4 月 1 日,但小于 5 月 1 日(这允许在 11:59:59pm 包含 4 月 30 日)
现在,我们进入了 5 月,贷款的变更将于 5 月 4 日完成。我们进入了新的一个月,@howFarBack 仍然允许截至 2020 年 12 月的旧应用程序有可能符合我们所知道的可以追溯到 2005 年的整个 table 应用程序。您始终使用最新数据,并且可以很容易地将@howFarBack 更改为最大回溯时间。这应该有助于满足您的性能需求。
根据另一位开发人员在 Whosebug 上的建议,我已经更新了我的查询如下,但我仍然需要进一步优化它。有人可以指导我如何最好地将索引应用于查询。
参见下面的查询:
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', 'corrected', 'Rejected', 'Processing', 'Captured', 'Reviewed', '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 给出了以下屏幕截图:(如何最大化 possible_keys 列中的信息
我更新了以下附加信息:
出于以下原因,我在 c 和 a 之间使用 OR:
a
是具有 66 列的父级 table,如果a
上的新条目具有 matching/existingippis
(a
上的唯一字段)a
中的某些列 updated/overwriten 包含来自新条目的数据,而条目中的其余数据作为新行插入c
(ippis
在 tablec
中不是唯一的。这是为了保留所有后续贷款请求的历史记录,同时不留出冗余空间在检索记录时,我需要大的
OR
子句来让我检查每个记录的所有实例的a
和c
tablestatus, date and current_loan
列与我的 WHERE 子句中的参数匹配的贷款记录。
的实际贷款申请的补充状态详细信息a
中始终会有完整的记录,但c
中不会始终有记录,除非有更多贷款请求使用相同的唯一 ID。a
包含 "who is the account person such as by unique ID", and the additional / supplemental status detail FOR THE FIRST LOAN, 随后,在第一笔贷款“c”之后将是附加/具有相同 Unique ID.如果“A”是在 3 月 12 日创建的,并且在 3 月 16 日创建了一个新的“c”记录。“A”记录也获得最后更新的标记为 Mar 16 因为它有一个对它有一些影响的子附件,而新的
进行了一些更改c
记录有它自己创建和更新的时间戳。a
记录的更新字段将为 blank/null,直到进行更改或存在c
记录,更新字段将为c
记录的 blank/null直到对c
记录
我希望这是可以理解的
我一直忘记这个术语,因为它很少出现在我身上,但是无论如何,您的索引不能通过使用 MONTH() 和 YEAR() 来优化,因为它们是基础数据的函数。通过应用日期范围,他们可以。因此,您可以保留 month/year,例如某些内容是在 2021 年 1 月创建并在 2021 年 3 月更新的,但此外,添加一个 "and c.date_created >= current_date AND current_date <= c.date_updated"
,如果其中包含创建日期,您可以使用该索引(在这种情况下,更新日期不太重要。
对于您的其他 table.
此外,当您从“a”到“c”进行左连接时 table,然后应用 where,这几乎就像您试图强制连接但仍然是左连接由于 OR.
我会将基于“c”的条件移动到左连接,然后只测试在那里找到的记录是否为 NULL。
虽然不清楚(我问的时候没有弄清楚),但我认为当创建新的“A”记录时,系统实际上可能会将创建日期同时放入创建日期和更新日期。如果是这种情况,那么我们只需要 query/concern 最后更新的日期字段与 activity 的当前 month/year。现在这是 where 子句的主要要求——不管“C”的基础 OR 条件如何 table.
此外,由于 month() 和 year() 不是 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, current_loan, 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', 'corrected', 'Rejected', 'Processing',
'Captured', 'Reviewed', 'top up')
AND (
a.current_loan = '1'
OR ( a.current_loan = '0'
AND a.loan_status IN ('Approved', 'Closed')
)
)
)
)
关闭查询评论
我修改了查询以及第一个 table 上的主索引以包含(第一个位置)记录的创建日期。我还添加了一个额外的变量@howFarBack 作为考虑贷款的最长回溯时间。我默认为 6 个月前。您是否需要考虑将超过 6 个月的给定帐户用于贷款?还是“a”帐户记录了可以追溯到 10 年前并想要包含的内容?我的印象是这是一个新的 LOAN APPLICATION 添加日期。如果是这样,允许在批准、最终确定、取消之前回溯 6 个月,仍然会阻止历史上处理尽可能多的月数数据。
在 WHERE 子句中,我为 CREATED_DATE >= @howFarBack 添加了显式添加。永远不可能创建子记录,更不用说在原始添加日期之前的任何时间进行更新了。这将强制只有当月 activity 或 FORWARD 符合资格。
例如:在 4 月 28 日创建贷款。所以 运行 查询,月初是 4 月 1 日,但小于 5 月 1 日(这允许在 11:59:59pm 包含 4 月 30 日)
现在,我们进入了 5 月,贷款的变更将于 5 月 4 日完成。我们进入了新的一个月,@howFarBack 仍然允许截至 2020 年 12 月的旧应用程序有可能符合我们所知道的可以追溯到 2005 年的整个 table 应用程序。您始终使用最新数据,并且可以很容易地将@howFarBack 更改为最大回溯时间。这应该有助于满足您的性能需求。