我有以下查询使用order by with limit。需要2分25秒才能获得16k左右的数据。我也做了正确的指数,但仍然保持缓慢。当仅应用LIMIT 20时也采用相同的时间。当删除ORDER BY时,查询在17秒内获取相同的数据。所有表都在latin1字符集中。请建议任何可能的解决方案。
SELECT
a.customer,
a.division AS division,
a.noitaziraa_id AS noitaziraaId,
DATE_FORMAT(a.request_date, '%m/%d/%Y') AS RequestDate,
a.request_date AS RequestDateSort,
DATE_FORMAT(noita.date_of_birth, '%m/%d/%Y') AS dob,
noita.date_of_birth AS dobSort,
IF(
a.noita_type = 'Noita Stay',
a.length_of_stay,
NULL
) AS requestedDays,
IF(
a.noita_type = 'Noita Stay',
CONCAT_WS(
',',
a.facility_provider_city,
a.facility_provider_state
),
''
) AS facilityCityState,
IF(
a.noita_type = 'Noita Stay',
IFNULL(
DATE_FORMAT(aips.admission_date, '%m/%d/%Y'),
''
),
''
) AS admitDate,
IF(
a.noita_type = 'Noita Stay',
aips.admission_date,
''
) AS admitDateSort,
IF(
a.noita_type = 'Noita Stay',
IFNULL(
DATE_FORMAT(
aipsd.discharge_date,
'%m/%d/%Y'
),
''
),
''
) AS dischargeDate,
IF(
a.noita_type = 'Noita Stay',
aipsd.discharge_date,
''
) AS dischargeDateSort,
IF(
a.noita_type = 'Noita Stay',
IFNULL(dl1.`description`, ''),
''
) AS dischargeDisposition,
a.gender,
a.age,
a.relationship AS relationship,
noita.groupid,
a.request_type AS requestType,
a.prog_status AS programStatus,
dl.description AS billingDetails,
a.referred_to_npi AS NPI,
a.program AS program,
CASE
WHEN a.status = 'OPEN'
THEN DATEDIFF(NOW(), a.auth_request_date)
ELSE 0
END AS 'daysSinceRequest',
a.first_name AS firstName,
a.last_name AS lastName,
dl2.description AS levelOfUrgency,
a.member_id AS memberId,
a.created_full_name AS createdFullName,
CONCAT_WS(
',',
COALESCE(a.assigned_to, NULL),
COALESCE(
a.auth_review_assigned_user_name,
NULL
),
COALESCE(
a.auth_con_review_assigned_user_name,
NULL
),
COALESCE(a.assigned_queue, NULL),
COALESCE(
a.auth_review_assigned_queue_name,
NULL
),
COALESCE(
a.auth_con_review_assigned_queue_name,
NULL
)
) AS assignedTo,
a.status,
DATE_FORMAT(a.opened_date, '%m/%d/%Y') AS openDate,
a.opened_date AS openDateSort,
DATE_FORMAT(a.closed_date, '%m/%d/%Y') AS closedDate,
a.closed_date AS closedDateSort,
a.noita_type AS authType,
a.facility_provider AS facilityProvider,
a.length_of_stay AS lengthOfStay,
DATE_FORMAT(a.requested_from, '%m/%d/%Y') AS authFromDate,
a.requested_from AS authFromDateSort,
DATE_FORMAT(a.requested_through, '%m/%d/%Y') AS authToDate,
a.requested_through AS authToDateSort,
a.pended,
a.diagnosis AS diagnosis,
a.diagnosis_desc AS diagDesc,
a.auth,
a.denied,
a.excluded,
a.admit_type AS admitType,
a.service_type AS serviceType,
a.proc,
a.proc_desc AS procDesc,
a.plan
FROM
main_table a
INNER JOIN noitaciary noita
ON noita.id = a.noitaciary_id
INNER JOIN usermanagement.`user` usr
ON a.created_by = usr.id
AND
CASE
WHEN CONCAT(usr.firstname, ' ', usr.lastname) IN ('a', 'b *', 'c',
'd', 'd', 'f')
THEN 1 = 1
ELSE (
COALESCE(usr.`employer`, '') NOT IN ('r', 's')
)
END
LEFT JOIN noitaziraa_ips AS aips
ON aips.noitaziraa_id = a.auth_id
LEFT JOIN db1.`noitaziraa_history` ah
ON ah.noitaziraa_id = a.noitaziraa_id
LEFT JOIN noitaziraa_ips_discharge AS aipsd
ON aipsd.noitaziraa_ips_id = aips.id
LEFT JOIN noitaziraa_phr AS aphr
ON aphr.noitaziraa_id = a.auth_id
LEFT JOIN noitaziraa_sp AS asp
ON asp.noitaziraa_id = a.auth_id
LEFT JOIN noitaziraa_decisions AS auth_dec
ON a.auth_id = auth_dec.noitaziraa_id
LEFT JOIN mytable AS aa
ON a.noitaziraa_id = aa.noitaziraa_id
LEFT JOIN db1.dw_lookup dl
ON auth_dec.details = dl.code
LEFT JOIN db1.`dw_lookup` dl1
ON dl1.`code` = aipsd.`discharge_diposition`
AND dl1.`data_type` = 'dataTypeName'
LEFT JOIN db1.dw_lookup dl2
ON aa.level_of_urgency = dl2.code
AND dl2.data_type = 'dataTypeName1'
LEFT JOIN
(SELECT
*
FROM
(SELECT
hh.noitaziraa_id,
hh.`status`
FROM
db1.`noitaziraa_history` hh,
main_table a
WHERE hh.noitaziraa_id = a.noitaziraa_id
AND hh.client = 'certainValue'
AND DATE(hh.last_updated) < '2017-12-01 00:00:00'
GROUP BY hh.`last_updated`
ORDER BY hh.last_updated DESC) tmp
GROUP BY noitaziraa_id) AS tps
ON tps.noitaziraa_id = a.noitaziraa_id
WHERE a.customer LIKE 'certainValue%'
AND a.status <> 'VOID'
AND DATE(auth_dec.requested_through) >= '2017-12-01 00:00:00'
AND DATE(auth_dec.requested_through) <= '2017-12-05 00:00:00'
AND DATE(a.opened_date) <= '2017-12-05 00:00:00'
AND (
(
DATE(ah.last_updated) BETWEEN '2017-12-01 00:00:00'
AND '2017-12-05 00:00:00'
AND ah.status IN (
'OPEN',
'CLOSED',
'REOPENED',
'CANCELED'
)
) || (
tps.noitaziraa_id = a.noitaziraa_id
AND tps.status IN (
'OPEN',
'CLOSED',
'REOPENED',
'CANCELED'
)
)
)
GROUP BY a.auth_id
ORDER BY groupid ASC
LIMIT 0, 20
noitaziraa_history表包含大量行,必须保持连接以满足我的要求,这需要花费大量时间。
答案 0 :(得分:4)
这需要逐步解决。
SELECT *
FROM
(
SELECT hh.noitaziraa_id, hh.`status`
FROM db1.`noitaziraa_history` hh, main_table a
WHERE hh.noitaziraa_id = a.noitaziraa_id
AND hh.client = 'certainValue'
AND DATE(hh.last_updated) < '2017-12-01 00:00:00'
GROUP BY hh.`last_updated`
ORDER BY hh.last_updated DESC
) tmp
GROUP BY noitaziraa_id
内部ORDER BY
将被忽略;摆脱它。然后询问GROUP BY
的两个级别是否真的有意义。
AND DATE(hh.last_updated) < '2017-12-01 00:00:00'
将其更改为
AND hh.last_updated < '2017-12-01'
原因:在函数(DATE
)中隐藏可能已编入索引的列会使其无法使用索引。
然后将此综合索引添加到hh
:
INDEX(client, noitaziraa_id, last_updated, status)
与此同时,你可能有一个严重的错误:为什么你在这个子查询和外部区域都指定了main_table a
?这是一个错误吗?
AND DATE(auth_dec.requested_through) >= '2017-12-01 00:00:00'
AND DATE(auth_dec.requested_through) <= '2017-12-05 00:00:00'
- &GT;
AND auth_dec.requested_through >= '2017-12-01'
AND auth_dec.requested_through < '2017-12-01' + INTERVAL 5 DAY
这些都没有使用,所以摆脱它们。这可能需要您在构造查询的代码上投入更多精力。 (或者是用手写的?)
LEFT JOIN noitaziraa_phr AS aphr ON aphr.noitaziraa_id = a.auth_id
LEFT JOIN noitaziraa_sp AS asp ON asp.noitaziraa_id = a.auth_id
LEFT JOIN
- 除非您需要,否则不要使用它。您不需要其中的一些 - 可以通过引用auth_dec
子句中的WHERE
来发现。
dl
,dl1
,dl2
- 这些位于LEFT JOINs
链的末尾。删除它们,并删除对它们中的列的引用。然后在执行SELECT
和ORDER BY
之后,在外面添加一个额外的LIMIT
图层以进入。这将减少来自&#34; lot&#34;只有20岁。
EXPLAIN
显示表格caseload
;查询没有这样的。请修理。
修正AND AND
错字。
我现在退出了。
答案 1 :(得分:1)
根据这个问题,您也应用了正确的索引。我想你是对的。然后,请避免在noitaziraa_history
表中使用LEFT JOIN,因为@Rick James也提到了这一点。如果可能,请确保在此表中加载数据,以便主表中的所有noitaziraa_id也在历史表中。现在,您可以应用INNER JOIN而不是正在使用的LEFT JOIN并查看结果。此外,根据Rick James的建议,重构目前似乎不合适或目前无用的所有内容。我确信如果主表中的同一行有多行数据,INNER JOIN将减少LEFT JOIN所用的时间。
更重要的是,如果您可以在JOIN期间使用nnoitaziraa_history
表格,请使用任何条件过滤器,就像您在下面的子查询中所做的那样:
INNER JOIN db1.`noitaziraa_history` ah
ON ah.noitaziraa_id = a.noitaziraa_id AND hh.client = 'certainValue' AND DATE(hh.last_updated) < '2017-12-01 00:00:00'
请更新,如果它适合你:)谢谢!