下面是我的示例查询,由于OPOS,POS4表中有很多记录(例如超过1000万条),因此执行时间很长。 where子句中的or条件对我造成了问题。
这是我的查询
SelecT DISTINCT T0.SaleID,T0.ParentID,T0.CustomerID from OPOS T0
Left JOIN OCRD C0 ON C0.CustomerID = T0.ParentID --SS / Dist (FOR CUST TYPE)
LEFT Join POS4 C1 ON T0.SaleID = C1.SaleID AND T0.ParentID = C1.ParentID AND C1.Type = 'C' AND C1.LevelType = 4 -- SS
LEFT Join POS4 C2 ON T0.SaleID = C2.SaleID AND T0.ParentID = C2.ParentID AND C2.Type = 'C' AND C2.LevelType = 2 -- DIST
LEFT Join POS4 C3 ON T0.SaleID = C3.SaleID AND T0.ParentID = C3.ParentID AND C3.Type = 'C' AND C3.LevelType = 3 -- DEALER
LEFT Join POS4 E1 ON T0.SaleID = E1.SaleID AND T0.ParentID = E1.ParentID AND E1.Type = 'E' -- LOGIN EMP USER(CUSTOMER // COMPANY)
LEFT Join POS4 E2 ON T0.SaleID = E2.SaleID AND T0.ParentID = E2.ParentID AND E2.Type = 'E' -- SELECTED EMP USER (COMPANY)
Where Convert(Date,T0.Date) >= @FromDate AND Convert(Date,T0.Date) <= @ToDate AND C0.Type = @SaleBy AND T0.OrderType IN (12, 13)
AND E1.TypeID = @LUserID AND E2.TypeID = @SUserID
AND (@SSID = 0 OR C1.TypeID = @SSID)
AND (@DistributorID = 0 OR C2.TypeID = @DistributorID)
AND (@DealerID = 0 OR C3.TypeID = @DealerID)
答案 0 :(得分:1)
查看结果字段,您只需要T0的结果,而联接实际上是“内部联接”(在WHERE中隐含)。而不是内部(或左侧)连接所有这些表,简单的EXISTS检查可能会更好。 如果您这样重写SQL怎么办? :
SelecT DISTINCT T0.SaleID,T0.ParentID,T0.CustomerID
from OPOS T0
-- Why should you ever need a conversion of a date field to date?
-- not using Date but Text?
Where T0.[Date] >= @FromDate AND T0.[Date] < @ToDate
AND EXISTS
(select * from OCRD C0
where C0.CustomerID = T0.ParentID and
C0.Type = @SaleBy AND T0.OrderType IN (12, 13)) --SS / Dist (FOR CUST TYPE)
AND EXISTS
(select * from POS4 E1
where T0.SaleID = E1.SaleID
AND T0.ParentID = E1.ParentID
AND E1.Type = 'E'
AND E1.TypeID = @LUserID) -- LOGIN EMP USER(CUSTOMER // COMPANY)
AND EXISTS
(Select * from POS4 E2
where T0.SaleID = E2.SaleID
AND T0.ParentID = E2.ParentID
AND E2.Type = 'E'
AND E2.TypeID = @SUserID)
) -- SELECTED EMP USER (COMPANY)
AND (@SSID = 0 OR
EXISTS
(select * from POS4 C1
where T0.SaleID = C1.SaleID AND
T0.ParentID = C1.ParentID AND
C1.Type = 'C' AND
C1.LevelType = 4 AND
C1.TypeID = @SSID)
) --SS
AND (@DistributorID = 0 OR
EXISTS
( select * from POS4 C2
where T0.SaleID = C2.SaleID
AND T0.ParentID = C2.ParentID
AND C2.Type = 'C'
AND C2.LevelType = 2
AND C2.TypeID = @DistributorID)
) -- DIST
AND (@DealerID = 0 OR
EXISTS
(select * from POS4 C3
where T0.SaleID = C3.SaleID
AND T0.ParentID = C3.ParentID
AND C3.Type = 'C'
AND C3.LevelType = 3
AND C3.TypeID = @DealerID)
); -- DEALER
编辑:在代码中编辑了检查日期的where部分。
Where T0.[Date] >= @FromDate AND T0.[Date] < @ToDate
这将受益于[日期]上的索引。还要注意,它使用> =和<作为运算符(不是<= @ToDate)。这是在MS SQL Server中执行日期时间范围查询的正确方法(日期时间值具有3ms的敏感性)。您以这样的方式提供@FromDate和@ToDate值:@FromDate包含要包含的第一个DateTime,而@ToDate是要排除的最小DateTime。
转换为日期,您只想检查日期,并说要返回2018年6月的所有记录作为示例。那么您的@FromDate将为“ 20180601”(隐式转换为Datetime的2018年6月1日00:00:00),而@toDate将为“ 20180701”(隐式转换为2018年7月1日00:00:00)。这恰好意味着2018年6月的所有记录。 哇,应该是:
t0.[Date] >= '20180601' and
t0.[Date] < '20180701'
完成后,它对应于:
Convert(date, t0.[Date]) >= '20180601' and
Convert(date, t0.[Date]) <= '20180630'
但无需将Datetime转换为日期,并精确返回请求日期的数据。