我有一个复杂的查询,需要总共4个表中的字段。我有一个内部连接语句,它有一个 SELECT
pending_corrections.sightinguid AS 'pending_corrections_sightinguid',
vehicle_ownership.id AS 'fk_vehicle_owner',
@bill_id AS 'fk_bills',
@nullValue AS 'fk_final_sightings_sightinguid',
TRIM(pending_corrections.corrected_plate) AS 'vrn',
pending_corrections.seenDate AS 'seen_date',
cameras.in_out AS 'in_out',
vehicle_vrn.fk_sysno AS 'fk_sysno',
cameras.zone AS 'fk_zones',
'0' AS 'auto_generated'
FROM
(pending_corrections
INNER JOIN cameras ON pending_corrections.camerauid = cameras.camera_id)
INNER JOIN
vehicle_vrn ON (pending_corrections.corrected_plate = vehicle_vrn.vrn500
OR pending_corrections.corrected_plate = vehicle_vrn.vrnno)
INNER JOIN
vehicle_ownership ON vehicle_vrn.fk_sysno = vehicle_ownership.fk_sysno
WHERE
pending_corrections.corrected_plate <> ''
AND pending_corrections.corrected_plate IS NOT NULL
AND pending_corrections.unable_to_correct <> '1'
AND pending_corrections.seenDate >= @dateFrom
AND pending_corrections.seenDate <= @dateTo
AND (cameras.in_out = 1 OR cameras.in_out = 0)
AND cameras.zone IN (SELECT
zone_number
FROM
zones
WHERE
fk_site = @siteId)
AND seenDate >= vehicle_vrn.vrn_start_date
AND (seenDate <= vehicle_vrn.vrn_end_date
OR vehicle_vrn.vrn_end_date IS NULL
OR vehicle_vrn.vrn_end_date = '0001-01-01 00:00:00')
AND seenDate >= vehicle_ownership.ownership_start_date
AND (seenDate <= vehicle_ownership.ownership_end_date
OR vehicle_ownership.ownership_end_date IS NULL
OR vehicle_ownership.ownership_end_date = '0001-01-01 00:00:00')
ORDER BY pending_corrections.corrected_plate , pending_corrections.seenDate ASC;
子句,这会大大减慢查询速度。
这是我的疑问:
OR
如何在其中一个连接中实现相同的效果但没有OR
? pending_corrections.corrected_plate
子句的原因是vrn500
值必须与vrnno
表中的vehicle_vrn
或1) Trigger 'Wiki A' change
2) Verify content on 'Wiki B'
列匹配。
答案 0 :(得分:1)
您可以使用IN表达式,例如:
,而不是使用带有OR的两个equals表达式FROM
(pending_corrections
INNER JOIN cameras ON pending_corrections.camerauid = cameras.camera_id)
INNER JOIN
vehicle_vrn ON pending_corrections.corrected_plate IN(vehicle_vrn.vrn500, vehicle_vrn.vrnno)
INNER JOIN
vehicle_ownership ON vehicle_vrn.fk_sysno = vehicle_ownership.fk_sysno
答案 1 :(得分:0)
执行计划是什么样的? SQL可能无法将此连接优化为散列或合并,因此只需执行表扫描。
有时使用OR,UNION运行良好。它的代码更多,但运行速度更快,因为SQL可以更好地优化它们。
; WITH PendingCorrectionsCte AS
(
SELECT pc.corrected_plate,
pc.seen_date,
c.in_out,
pc.sightinguid AS 'pending_corrections_sightinguid',
FROM pending_corrections pc
INNER JOIN cameras c ON pending_corrections.camerauid = cameras.camera_id
WHERE pc.seenDate BETWEEN '2015-01-01 00:00:00' AND '2015-01-31 23:59:59'
AND NULLIF(LTRIM(pc.corrected_plate), '') IS NOT NULL
AND pending_corrections.unable_to_correct <> '1'
AND pending_corrections.seenDate >= @dateFrom
AND pending_corrections.seenDate <= @dateTo
AND c.in_out IN (0, 1)
AND c.zone IN (SELECT zone_number FROM zones WHERE fk_site = @siteId)
),
VrnCte AS
(
SELECT pc.corrected_plate,
pc.seen_date,
vrn.fk_sysno,
pc.in_out,
pc.pending_corrections_sightinguid
FROM PendingCorrectionsCte pc
INNER JOIN vehicle_vrn vrn ON pc.corrected_plate = vehicle_vrn.vrn500
-- Could also do this inline in the where clause, but chaining isnull and nullif could get hard to read
CROSS APPLY (SELECT NULLIF(vrn.vrn_end_date, '0001-01-01 00:00:00') AS value) vrn_end_date
WHERE pc.seenDate BETWEEN vrn.vrn_start_date AND ISNULL(vrn_end_date.value, seenDate)
UNION
SELECT pc.corrected_plate,
pc.seenDate,
vrn.fk_sysno,
pc.in_out,
pc.pending_corrections_sightinguid
FROM pending_corrections pc
INNER JOIN vehicle_vrn vrn ON pc.corrected_plate = vehicle_vrn.vrnno
-- Could also do this inline in the where clause, but chaining isnull and nullif could get hard to read
CROSS APPLY (SELECT NULLIF(vrn.vrn_end_date, '0001-01-01 00:00:00') AS value) vrn_end_date
WHERE pc.seenDate BETWEEN vrn.vrn_start_date AND ISNULL(vrn_end_date.value, seenDate)
)
SELECT pending_corrections.sightinguid AS 'pending_corrections_sightinguid',
vo.id AS 'fk_vehicle_owner',
@bill_id AS 'fk_bills',
@nullValue AS 'fk_final_sightings_sightinguid',
TRIM(VrnCte.corrected_plate) AS 'vrn',
VrnCte.seenDate AS 'seen_date',
VrnCte.in_out AS 'in_out',
VrnCte.fk_sysno AS 'fk_sysno',
VrnCte.pending_corrections_sightinguid
'0' AS 'auto_generated'
FROM VrnCte
INNER JOIN vehicle_ownership vo ON VrnCte.fk_sysno = vo.fk_sysno
CROSS APPLY (SELECT NULLIF(vo.ownership_end_date, '0001-01-01 00:00:00') AS value) ownership_end_date
WHERE VrnCte.seenDate BETWEEN vehicle_ownership.ownership_start_date AND ISNULL(ownership_end_date.value, seenDate)
ORDER BY
VrnCte.corrected_plate,
VrnCte.seenDate ASC
答案 2 :(得分:0)
您可以使用OR
替换第一个IN()
,如Scott提到的那样
pending_corrections.corrected_plate IN (vehicle_vrn.vrn500, vehicle_vrn.vrnno)
如果您可以UPDATE
vrn_end_date
和ownership_end_date
列'0001-01-01 00:00:00'
到NULL
,其他OR
条件可以简化为< / p>
AND (seenDate <= IFNULL(vehicle_vrn.vrn_end_date, seenDate))