2

我的数据库有大约 15 万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% 的成本。我完全困惑在这一点上我应该做什么。我想敲我的头,但我不能,因为周围有其他人。请建议我该怎么办?

4

3 回答 3

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

我从来没有UNION用 CTE 做过 a,所以你可能需要一些额外的括号来使它合法。也ORDER BY适用于整个结果。我会把它留作练习。

关键是INNER JOIN将能够使用索引 on nm.Name,而第二个子句将能够进行索引反半连接。两个索引查询应该比一个未索引查询快得多。

于 2013-04-04T14:07:32.053 回答
2

对于它的价值,这里有一些 SQLFiddle来测试任何语法。

到目前为止,最简单的方法是确保NameTypes按顺序插入s Name,因此NameTypeID按字母顺序分配 s。

在这种情况下,无需加入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;
于 2013-04-04T12:36:26.483 回答
1

您可以尝试几件事:

  1. 使聚集索引以名称开头......拥有一个广泛的聚集索引不是很有效,但试一试,看看它是否会停止排序发生

  2. 永久创建一个包含订单号的列。这取决于您的表格的更新频率。

请发布您的表和索引定义。

于 2013-04-04T11:39:10.403 回答