我有以下SQL,
SELECT U.ID AS UserID
,U.LoginName AS Name
,PV.Time AS [Time]
,PV.URL AS [Url]
,P.Name AS [Product 1 Name]
,P.SKU AS [Product 1 SKU]
,P.ModelNumber AS [Product 1 Model Number]
,P2.Name AS [Product 2 Name]
,P2.SKU AS [Product 2 SKU]
,P2.ModelNumber AS [Product 2 Model Number]
,ISNULL((select TOP 1 Value from AttributesValues AV INNER JOIN Attributes A ON AV.AttributeID = A.ID WHERE AV.ProductID = P.ID AND A.RetailerID = 23 AND A.CODE = 'metadata-department'),'') AS Department
,ISNULL((select TOP 1 Value from AttributesValues AV INNER JOIN Attributes A ON AV.AttributeID = A.ID WHERE AV.ProductID = P.ID AND A.RetailerID = 23 AND A.CODE = 'metadata-group'),'') AS Department
,ISNULL((select TOP 1 Value from AttributesValues AV INNER JOIN Attributes A ON AV.AttributeID = A.ID WHERE AV.ProductID = P.ID AND A.RetailerID = 23 AND A.CODE = 'metadata-subgroup'),'') AS SubGroup
,C.Browser AS [Browser]
,C.BrowserVersion AS [Browser Version]
,C.IPAddress AS [IP Address]
,C.UserAgent AS [User Agent]
,C.UserLanguage AS [User Language]
,PV.PageType AS [Page Type]
FROM PageVisits PV
INNER JOIN Users U ON U.ID = PV.UserID
INNER JOIN Clients C ON C.ID = PV.ClientID
INNER JOIN Products P ON P.id = PV.P1ID
LEFT OUTER JOIN Products P2 ON P2.id = PV.P2ID
WHERE P.RetailerID = 23
AND PV.UserID IS NOT NULL
AND PV.PageType IN ('Product','Compare Products')
AND PV.[Time] >= '{0}' AND PV.[Time] < '{1}'
问题是这个子查询,
,ISNULL((select TOP 1 Value from AttributesValues AV
INNER JOIN Attributes A ON AV.AttributeID = A.ID
WHERE AV.ProductID = P.ID AND A.RetailerID = 23
AND A.CODE = 'metadata-department'),'') AS Department
我在这里用了3次。唯一的区别是A.CODE =
。我怎样才能改善这个
答案 0 :(得分:3)
您应该首先尝试为查询构建索引:
create index on Attributes(RetailerId, Code, Id);
create index on AttributeValues(AttributeId, ProductId, Value);
子查询的处理应该只是几个索引查找。
答案 1 :(得分:2)
始终将ORDER BY
与TOP
一起使用。否则,您将获得不确定的结果,具体取决于SQL引擎将如何获取相关行。
如果确实不需要TOP 1
,即如果子查询总是返回1(或0)行而没有TOP,那么您可以将OUTER APPLY
与MAX()
一起使用:
SELECT
---
,COALESCE(X.Department, '') AS Department
,COALESCE(X.[Group], '') AS [Group]
,COALESCE(X.SubGroup, '') AS SubGroup
---
FROM PageVisits PV
INNER JOIN Users U ON U.ID = PV.UserID
INNER JOIN Clients C ON C.ID = PV.ClientID
INNER JOIN Products P ON P.id = PV.P1ID
LEFT OUTER JOIN Products P2 ON P2.id = PV.P2ID
OUTER APPLY
( SELECT MAX(CASE WHEN A.CODE = 'metadata-department' THEN AV.Value END)
AS Department
,MAX(CASE WHEN A.CODE = 'metadata-group' THEN AV.Value END)
AS [Group]
,MAX(CASE WHEN A.CODE = 'metadata-subqroup' THEN AV.Value END)
AS SubGroup
FROM AttributesValues AV
INNER JOIN Attributes A ON AV.AttributeID = A.ID
WHERE AV.ProductID = P.ID
AND A.RetailerID = 23
) X
WHERE
--- ;
答案 2 :(得分:1)
你可以定义一个CTE,它基本上是一个内联视图,以避免重新输入查询,但它实际上不会改变正在执行3次的查询,它只会整理代码:
WITH CTE AS
( SELECT AV.ProductID, AV.Value, A.Code
FROM AttributesValues AV
INNER JOIN Attributes A ON AV.AttributeID = A.ID
WHERE A.RetailerID = 23
)
SELECT U.ID AS UserID
,U.LoginName AS Name
,PV.Time AS [Time]
,PV.URL AS [Url]
,P.Name AS [Product 1 Name]
,P.SKU AS [Product 1 SKU]
,P.ModelNumber AS [Product 1 Model Number]
,P2.Name AS [Product 2 Name]
,P2.SKU AS [Product 2 SKU]
,P2.ModelNumber AS [Product 2 Model Number]
,ISNULL((SELECT TOP 1 Value FROM CTE WHERE CTE.ProductID = P.ID AND CTE.CODE = 'metadata-department'),'') AS Department
,ISNULL((SELECT TOP 1 Value FROM CTE WHERE CTE.ProductID = P.ID AND CTE.CODE = 'metadata-group'),'') AS [Group]
,ISNULL((SELECT TOP 1 Value FROM CTE WHERE CTE.ProductID = P.ID AND CTE.CODE = 'metadata-subgroup'),'') AS SubGroup
,C.Browser AS [Browser]
,C.BrowserVersion AS [Browser Version]
,C.IPAddress AS [IP Address]
,C.UserAgent AS [User Agent]
,C.UserLanguage AS [User Language]
,PV.PageType AS [Page Type]
FROM PageVisits PV
INNER JOIN Users U ON U.ID = PV.UserID
INNER JOIN Clients C ON C.ID = PV.ClientID
INNER JOIN Products P ON P.id = PV.P1ID
LEFT OUTER JOIN Products P2 ON P2.id = PV.P2ID
WHERE P.RetailerID = 23
AND PV.UserID IS NOT NULL
AND PV.PageType IN ('Product','Compare Products')
AND PV.[Time] >= '{0}' AND PV.[Time] < '{1}'
值得注意的是,TOP 1
没有订单,这会给你带来不确定的结果(除非有唯一的约束来确保只有一行可以返回)。
我也倾向于将其重写为JOIN以减少AttributesValues
和Attributes
上的表读取次数。您可以通过在属性值上使用PIVOT来执行此操作:
WITH CTE AS
( SELECT AV.ProductID,
AV.Value,
A.Code ,
RowNumber = ROW_NUMBER() OVER(PARTITION BY AV.ProductID, A.Code ORDER BY AV.Value)
FROM AttributesValues AV
INNER JOIN Attributes A ON AV.AttributeID = A.ID
WHERE A.RetailerID = 23
AND AV.Code IN ('metadata-department', 'metadata-group', 'metadata-subgroup')
), AV AS
( SELECT pvt.ProductID,
pvt.[metadata-department],
pvt.[metadata-group],
pvt.[metadata-subgroup]
FROM CTE
PIVOT
( MAX(Value)
FOR Code IN ([metadata-department], [metadata-group], [metadata-subgroup])
) pvt
WHERE pvt.RowNumber = 1
)
SELECT U.ID AS UserID
,U.LoginName AS Name
,PV.Time AS [Time]
,PV.URL AS [Url]
,P.Name AS [Product 1 Name]
,P.SKU AS [Product 1 SKU]
,P.ModelNumber AS [Product 1 Model Number]
,P2.Name AS [Product 2 Name]
,P2.SKU AS [Product 2 SKU]
,P2.ModelNumber AS [Product 2 Model Number]
,ISNULL(AV.[metadata-department],'') AS Department
,ISNULL(AV.[metadata-group],'') AS [Group]
,ISNULL(AV.[metadata-subgroup],'') AS SubGroup
,C.Browser AS [Browser]
,C.BrowserVersion AS [Browser Version]
,C.IPAddress AS [IP Address]
,C.UserAgent AS [User Agent]
,C.UserLanguage AS [User Language]
,PV.PageType AS [Page Type]
FROM PageVisits PV
INNER JOIN Users U ON U.ID = PV.UserID
INNER JOIN Clients C ON C.ID = PV.ClientID
INNER JOIN Products P ON P.id = PV.P1ID
LEFT OUTER JOIN Products P2 ON P2.id = PV.P2ID
LEFT OUTER JOIN AV ON AV.ProductID = p.ID
WHERE P.RetailerID = 23
AND PV.UserID IS NOT NULL
AND PV.PageType IN ('Product','Compare Products')
AND PV.[Time] >= '{0}' AND PV.[Time] < '{1}'
N&gt; B 您可能希望更改ORDER BY
中的ROW_NUMBER
,以影响针对productID和Code的每个组合返回的值(如果这是唯一的虽然顺序是无关紧要的)*