sql - 具有大量表连接的查询的 SQL 性能调优
问题描述
我有一些 SQL,我一直在努力让它尽可能快。但是,因为我们有大量数据的表,SQL 需要很长时间才能运行。
更多信息:
x86_64-redhat-linux-gnu 上的 PostgreSQL 9.2.24,由 gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28) 编译,64 位
问题
有什么指针可以用来加快速度吗?
SELECT DISTINCT
trip.travel_order_num as order_num,
min(contact.fname || ' ' || contact.sname) as traveller,
min(agentcontact.fname || ' ' || agentcontact.sname) as agent,
min(employee.staff_code) as staff_code,
trip.projectnumber,
min(lob.name) as cost_centre,
trip.start_date,
trip.end_date,
DATE(trip.end_date) - DATE(trip.start_date) + 1 as number_of_days,
DATE(trip.start_date) - DATE(reqcreationdate) as days_requested_in_advance,
trip.created as tripcreationdate,
trip.recoverablecost,
tripstatus.name AS status,
trip.company_id,
trip.eventtypes,
trip.trip_reason,
min(to_char(timetofirstbooking.earliestbookingdate - trip.reqcreationdate, 'FMDD HH24:MI:SS')) as dates_taken_to_book,
min(COALESCE(paidaccommodation.paid_accomtot, 0.00)) AS paid_accomtot,
min(COALESCE(booked_accommodation_total, 0.00)) as booked_accommodation_total,
min(COALESCE(null, 0.00)) AS paid_cartot,
min(COALESCE(bookedcarhire.booked_car_hire_total, 0.00)) as booked_car_hire_total,
min(COALESCE(paidflightfare.allstatuses_flighttot, 0.00)) AS allstatuses_flighttot,
min(COALESCE(paidflightfare.savings, 0.00)) AS flightsavings_tot,
min(COALESCE(paidflightfare.publishedfare, 0.00)) AS flightpublishedfare_tot,
min(COALESCE(tripservicefeepaid.feeamount, 0.00)) as servicefee,
min(COALESCE(tripchangeservicefeepaid.feeamount, 0.00)) as changeservicefee,
min(COALESCE(otheritemspaid.amount, 0.00)) as otherfee,
CASE
WHEN trip.requester_personid IS NOT NULL THEN min(requestercontact.fname || ' ' || requestercontact.sname)
WHEN trip.requester_personid IS NULL THEN min(agentcontact.fname || ' ' || agentcontact.sname)
END as requester,
CASE
WHEN min(tas.lastname) IS NOT NULL AND min(tas.staffcode) IS NOT NULL THEN string_agg(DISTINCT(CONCAT(tas.firstname,' ',tas.lastname, ' (',tas.staffcode,')')),', ')
WHEN min(tas.lastname) IS NOT NULL THEN string_agg(DISTINCT(CONCAT(tas.firstname,' ',tas.lastname)),', ')
ELSE ''
END as approver,
min(bob.approvalRequestedDate) as approvalrequesteddate,
max(bob.apprConcDate) as approvalconclusiondate,
extract(EPOCH from min(timetoapprove))/3600 as timetoapprove
FROM TRIP
LEFT JOIN TRIPTRAVELLERMAP ON triptravellermap.tripid = trip.trip_id
LEFT JOIN FLIGHTFARE ON flightfare.triptravid = triptravellermap.triptravid
LEFT JOIN TRAVELAGENT ON travelagent.agentid = trip.agent_id
LEFT JOIN CONTACT as agentcontact ON agentcontact.member_id = travelagent.memberid
LEFT JOIN ITEM ON item.itemid = trip.itemid
LEFT JOIN LOB ON lob.lobid = item.lobid
LEFT JOIN TRIPSTATUS ON tripstatus.statusid = trip.status
LEFT JOIN PERSON_CONTACT ON person_contact.person_personid = triptravellermap.personid
LEFT JOIN CONTACT ON contact.contact_id = person_contact.personaldetails_contact_id
LEFT JOIN PERSON_EMPLOYEE ON person_employee.person_personid = triptravellermap.personid
LEFT JOIN EMPLOYEE ON employee.employee_id = person_employee.employmentdetails_employee_id
LEFT JOIN TRIPREQUIREMENTSMAPPING ON triprequirementsmapping.tripid = trip.trip_id
LEFT JOIN TRIPREQUIREMENTS ON triprequirements.uri = triprequirementsmapping.corporatetravelrequesturi
LEFT JOIN PERSON_CONTACT AS requesterperson ON requesterperson.person_personid = trip.requester_personid
LEFT JOIN CONTACT AS requestercontact ON requestercontact.contact_id = requesterperson.personaldetails_contact_id
LEFT JOIN trip_approver_snapshot tas ON trip.trip_id=tas.trip_id
/* PAID ACCOMMODATION */
LEFT JOIN (SELECT trip.trip_id, SUM(lineitems.amount) as paid_accomtot
FROM TRIP
INNER JOIN RESERVATION ON reservation.trip_id = trip.trip_id
INNER JOIN ACCOMMODATION ON accommodation.reservationid = reservation.reservationid
INNER JOIN LINEITEMS ON lineitems.invoiceid = accommodation.invoiceid
WHERE accommodation.created >= '2021-05-01' and accommodation.created <= ('2021-05-23')
AND accommodation.resstatus <> 2
GROUP BY trip.trip_id) AS paidaccommodation ON paidaccommodation.trip_id = trip.trip_id
/* BOOKED ACCOMMODATION */
LEFT JOIN (SELECT trip.trip_id, SUM(accommodation.totalaftertax) as booked_accommodation_total
FROM TRIP
INNER JOIN RESERVATION ON reservation.trip_id = trip.trip_id
INNER JOIN ACCOMMODATION ON accommodation.reservationid = reservation.reservationid
WHERE accommodation.created >= '2021-05-01' AND accommodation.created <= '2021-05-23'
AND accommodation.invoiceid IS NULL AND accommodation.resstatus <> 2
GROUP BY trip.trip_id) AS bookedaccommodation ON bookedaccommodation.trip_id = trip.trip_id
/* PAID CARRENTAL */
LEFT JOIN (SELECT trip.trip_id, SUM(carrental.rental_price) as booked_car_hire_total
FROM TRIP
INNER JOIN RESERVATION ON reservation.trip_id = trip.trip_id
INNER JOIN CARRENTAL ON carrental.reservationid = reservation.reservationid
WHERE carrental.created >= '2021-05-01' AND carrental.created <= '2021-05-23' AND carrental.status <> 2
GROUP BY trip.trip_id) AS bookedcarhire ON bookedcarhire.trip_id = trip.trip_id
/* PAID FLIGHT DETAILS */
LEFT JOIN ( SELECT trip.trip_id, SUM(flightfare.totalfare) as allstatuses_flighttot, SUM(flightfare.savings) as savings, SUM(flightfare.publishedfare) as publishedfare, MIN(flightfare.created) as earliestbooking
FROM TRIP
INNER JOIN TRIPTRAVELLERMAP ON triptravellermap.tripid = trip.trip_id
INNER JOIN FLIGHTFARE ON flightfare.triptravid = triptravellermap.triptravid
WHERE flightfare.created >= '2021-05-01' AND flightfare.created <= '2021-05-23'
AND (flightfare.status <> 2 OR (flightfare.status = 2 AND flightfare.ticketed = 1))
AND NOT(flightfare.ticketed = 0 AND flightfare.tickettimelimit < CURRENT_TIMESTAMP)
GROUP BY trip.trip_id ) AS paidflightfare ON paidflightfare.trip_id = trip.trip_id
/* TIME TO FIRST BOOKING */
LEFT JOIN (SELECT cc.trip_id, MIN(earliest_booked_date) as earliestbookingdate
FROM(
(SELECT trip.trip_id, MIN(flightfare.created) as earliest_booked_date
FROM TRIP
INNER JOIN TRIPTRAVELLERMAP ON triptravellermap.tripid = trip.trip_id
INNER JOIN FLIGHTFARE ON flightfare.triptravid = triptravellermap.triptravid
GROUP BY trip.trip_id )
UNION
(SELECT trip.trip_id, MIN(carrental.created) as earliest_booked_date
FROM TRIP
INNER JOIN RESERVATION ON reservation.trip_id = trip.trip_id
INNER JOIN CARRENTAL ON carrental.reservationid = reservation.reservationid
GROUP BY trip.trip_id)
UNION
(SELECT trip.trip_id, MIN(accommodation.created) as earliest_booked_date
FROM TRIP
INNER JOIN RESERVATION ON reservation.trip_id = trip.trip_id
INNER JOIN ACCOMMODATION ON accommodation.reservationid = reservation.reservationid
GROUP BY trip.trip_id)
) as cc GROUP BY cc.trip_id) AS timetofirstbooking ON timetofirstbooking.trip_id = trip.trip_id
/* TRIP FEES */
LEFT JOIN (SELECT trip.trip_id, SUM(tripfee.feeamount + tripfee.feeamountvat) as feeamount
FROM TRIP
INNER JOIN TRIPFEE ON tripfee.tripid = trip.trip_id
GROUP BY trip.trip_id) AS tripservicefeepaid ON tripservicefeepaid.trip_id = trip.trip_id
/* TRIP CHANGE FEES */
LEFT JOIN (SELECT trip.trip_id, SUM(tripfee.feeamount + tripfee.feeamountvat) as feeamount
FROM TRIP
INNER JOIN TRIPFEE ON tripfee.tripid = trip.trip_id
WHERE tripfee.tripfeetype = 9
GROUP BY trip.trip_id) AS tripchangeservicefeepaid ON tripchangeservicefeepaid.trip_id = trip.trip_id
/* OTHER ITEMS PAID */
LEFT JOIN (SELECT trip.trip_id, SUM(otheritems.amount + otheritems.vat) as amount
FROM TRIP
INNER JOIN OTHERITEMS ON otheritems.tripid = trip.trip_id
GROUP BY trip.trip_id) AS otheritemspaid ON otheritemspaid.trip_id = trip.trip_id
LEFT JOIN (
SELECT requested,max(conclusiondate) as apprConcDate , max(requestedDate) as approvalRequestedDate, max(conclusiondate)- max(requestedDate) as timetoapprove
FROM approvalsubmission
left join triprequirements on approvalsubmission.requested=triprequirements.uri
where approvalsubmission.conclusion='APPROVED'
group by requested) as bob on bob.requested = triprequirements.uri
WHERE
trip.trip_id IN (SELECT DISTINCT(trip_id) FROM reservation WHERE reservation.created >= ('2021-05-01') AND reservation.created <= ('2021-05-23'))
--AND LOWER(employee.staff_code) LIKE LOWER('$P!{staffCode')
AND trip.status <> 2
AND trip.company_id = 6632
--AND $P!{costCentreCompanySwitcher}
group by trip.trip_id, tripstatus.name
ORDER BY min(lob.name)
解决方案
固定的:
status
从 group by 子句中删除:
max(tripstatus.name) AS status,
...
group by trip.trip_id
推荐阅读
- postgresql - 是否可以使用 postgres 外部数据包装器在不同的服务器上重定向 SELECT 语句
- c++ - 将 int 数组转换为字符串
- javascript - ASP.NET 按钮,OnClientClick 不起作用
- flutter - 错误:无法无条件调用方法“[]”,因为接收者可以为“null”
- r - 如何根据 Shiny rHandsontable 中的另一列自动填充列的值?
- sql - 即使 SQL 中不满足条件,编译器似乎也会评估每个 if 语句
- python - 如何提取文本并将它们放入字典?
- c++ - 让我的库的用户也可以使用原始值和类名调用函数
- android - Android,以检测模式运行常规应用程序(仅限 adb + 调试)
- javascript - WebDataRocks 中的“EventEmitter”类型不存在属性“下一个”