我的数据库有大约150K DocumentNames
条记录,而我所做的只是与NameTypes
的简单联接。 NameTypeID是DocumentNames中的外键。
这是我的疑问:
With cte as
(
Select ROW_NUMBER() OVER
(Order By nm.Name asc )
peta_rn,
dn.DocumentNameID,
dn.DocumentID
From DocumentNames dn
Left Join NameTypes nm On dn.NameTypeID = nm.NameTypeID
)
Select * from cte Where peta_rn >= 10000 And peta_rn <= 10050
这是截图:
排序需要90%的成本。我完全感到困惑,此时我该怎么做。我想敲我的头,但我不能,因为周围还有其他人。请建议我该怎么做?
答案 0 :(得分:3)
如果由于某些任意原因(如求职面试),您需要优化此类查询,请尝试UNION
。
[已更正以识别别名列]
With cte as
(
Select ROW_NUMBER() OVER
(Order By nm.Name asc ) AS
peta_rn,
dn.DocumentNameID,
dn.DocumentID
From DocumentNames dn
INNER Join NameTypes nm On dn.NameTypeID = nm.NameTypeID /* note change */
),
cte2 as
(
Select ROW_NUMBER() OVER
() AS /* yes, this is random */
peta_rn,
dn.DocumentNameID,
dn.DocumentID
From DocumentNames dn
WHERE dn.NameTypeID NOT IN SELECT (nm.NameTypeID FROM NameTypes nm)
)
Select * from cte Where peta_rn >= 10000 And peta_rn <= 10050
UNION
Select * from cte2 Where peta_rn >= 10000 And peta_rn <= 10050
我从未对CTE进行UNION
,因此您可能需要一些额外的括号才能使其合法化。整个结果也是ORDER BY
。我会把它留作练习。
关键是INNER JOIN
将能够使用nm.Name
上的索引,而第二个子句将能够执行索引的反半连接。两个索引查询应该比一个未编制索引的查询快得多。
答案 1 :(得分:2)
对于它的价值,这里是some SQLFiddle来测试任何语法。
到目前为止,最简单的方法是确保以NameTypes
顺序插入Name
,因此NameTypeID
按字母顺序分配。
在这种情况下,无需加入NameTypes
表。你可以这样做,
WITH [CTE] AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY [NameTypeID] ASC) [PetaRN],
[DocumentNameID],
[DocumentID]
FROM
[DocumentNames]
)
SELECT
[PetaRN],
[DocumentNameID],
[DocumentID]
FROM
[CTE]
WHERE
[PetaRN] BETWEEN 10000 AND 10050
ORDER BY
[PetaRN] ASC;
怎么样
WITH [CTE] AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY [NameTypeID] ASC) [PetaRN],
[DocumentNameID],
[DocumentID]
FROM
[DocumentNames]
)
SELECT TOP 50
[PetaRN],
[DocumentNameID],
[DocumentID]
FROM
[CTE]
WHERE
[PetaRN] >= 10000
ORDER BY
[PetaRN] ASC;
在SQL 2005上测试大型数据集时,我注意到CTE对大型结果集的效果不佳,这可能与服务器上的资源可用性有关。反直觉使用临时表可能会更快。这也允许您索引行号,允许快速页面选择,但这必须抵消插入成本。试试吧,看看。
CREATE TABLE #Peta
(
[PetaRN] BigInt NOT NULL CONSTRAINT [PK_Peta] PRIMARY KEY CLUSTERED,
[DocumentNameID] Int NOT NULL,
[DocumentID] Int NOT NULL
);
INSERT #Peta
SELECT
ROW_NUMBER() OVER (ORDER BY [NameTypeID] ASC) [PetaRN],
[DocumentNameID],
[DocumentID]
FROM
[DocumentNames];
SELECT TOP 50
[PetaRN],
[DocumentNameID],
[DocumentID]
FROM
#Peta
WHERE
[PetaRN] >= 10000
ORDER BY
[PetaRN] ASC;
DROP TABLE #Peta;
答案 2 :(得分:1)
你可以尝试一些事情:
使聚集索引以Name开头...使用宽聚簇索引效率不高但是给它一个去看它是否会停止排序
永久创建一个包含订单号的列。这取决于您的表的更新频率。
请发布您的表格和索引定义。