Sql server SQL Server 2005 CTE性能—大量逻辑读取

Sql server SQL Server 2005 CTE性能—大量逻辑读取,sql-server,sql-server-2005,common-table-expression,sqlperformance,Sql Server,Sql Server 2005,Common Table Expression,Sqlperformance,我有一个CTE查询,它似乎导致了大量的逻辑读取(或者可能没有)。我已经运行了SQL Server Profiler跟踪,而此查询似乎始终是运行时间最长的查询之一。(每次点击页面都会调用它) 基本上,我想知道我的CTE是否得到了正确的优化,或者是否可以改进 SET STATISTICS IO ON; GO ;WITH cte (PageId, PageTitle, PageType, PageHeadingId, ParentPage, InNavigation, OrgLevel, So

我有一个CTE查询,它似乎导致了大量的逻辑读取(或者可能没有)。我已经运行了SQL Server Profiler跟踪,而此查询似乎始终是运行时间最长的查询之一。(每次点击页面都会调用它)

基本上,我想知道我的CTE是否得到了正确的优化,或者是否可以改进

SET STATISTICS IO ON;
GO
    ;WITH cte (PageId, PageTitle, PageType, PageHeadingId, ParentPage, InNavigation, OrgLevel, SortKey, PageOrder, PathLength, PathName, Active) AS
     (
      SELECT
        PageId, 
        PageTitle,
        PageType,
        PageHeadingId,
        ParentPage, 
        InNavigation,
        0, 
        CAST (PageOrder  AS VARBINARY(200)), 
        PageOrder, 
        0 AS PathLength, 
        CAST('' as varchar(300)) AS PathName,
        Active
       FROM dbo.ContentPage
       WHERE ParentPage = 0
        AND InNavigation = 1
      UNION ALL
      SELECT
        b.PageId, 
        b.PageTitle, 
        b.PageType,
        b.PageHeadingId,
        b.ParentPage,
        b.InNavigation, 
        cte.OrgLevel+1,
        CAST(cte.SortKey + CAST (b.PageOrder AS BINARY(4)) AS VARBINARY(200)),
        b.PageOrder, 
        ((cte.OrgLevel+1) + len('....'+b.PageTitle)) as PathLength,
        CAST ((cte.PathName+'....') AS VARCHAR(300)) AS PathName,
        b.Active
       FROM dbo.ContentPage b
         JOIN cte ON b.ParentPage = cte.PageId
       WHERE b.PageType NOT IN (4, 8, 11, 12, 14)
        -- Remove specific page types from the ContentPage table
     )
    SELECT *, (PathName+PageTitle) AS Hierarchy 
    FROM cte WHERE InNavigation = 1     
    ORDER BY SortKey--, PageOrder
SET STATISTICS IO OFF;
GO
如果我离开这一行:

WHERE b.PageType NOT IN (4, 8, 11, 12, 14)
输出,则逻辑读取的数量从约8500跳到约13000

(查询所做的是在ASP.NET中构建一个下拉菜单层次结构)如果逻辑读取正常,那么我假设我必须想出另一种方法来缓存/存储此菜单(每周更新2或3次)

谢谢

ContentPage的表结构

CREATE TABLE [dbo].[ContentPage](
    [PageId] [int] IDENTITY(1,1) NOT NULL,
    [PageTitle] [nvarchar](150) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
    [PageQuote] [nvarchar](400) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [MetaKeywords] [nvarchar](200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [MetaDescription] [ntext] COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [PageContent] [ntext] COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [Active] [bit] NOT NULL CONSTRAINT [DF_ContentPage_Active]  DEFAULT ((0)),
    [InNavigation] [bit] NOT NULL CONSTRAINT [DF_ContentPage_InNavigation]  DEFAULT ((1)),
    [PageOrder] [int] NOT NULL CONSTRAINT [DF_ContentPage_PageOrder]  DEFAULT ((50)),
    [ParentPage] [int] NOT NULL CONSTRAINT [DF_ContentPage_ParentPage]  DEFAULT ((0)),
    [PageType] [int] NOT NULL CONSTRAINT [DF_ContentPage_PageType]  DEFAULT ((1)),
    [CreatedBy] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [CreatedOn] [datetime] NULL,
    [ModifiedBy] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [ModifiedOn] [datetime] NULL,
    [PageViews] [int] NOT NULL CONSTRAINT [DF_ContentPage_PageViews]  DEFAULT ((0)),
    [Emailed] [int] NOT NULL CONSTRAINT [DF_ContentPage_Emailed]  DEFAULT ((0)),
    [Emailable] [bit] NOT NULL CONSTRAINT [DF_ContentPage_Emailable]  DEFAULT ((1)),
    [Printable] [bit] NOT NULL CONSTRAINT [DF_ContentPage_Printable]  DEFAULT ((1)),
    [ContactButton] [bit] NOT NULL CONSTRAINT [DF_ContentPage_PDFable]  DEFAULT ((0)),
    [PageHeadingId] [int] NULL CONSTRAINT [DF_ContentPage_PadeHeadingId]  DEFAULT ((0)),
    [AlternativeTitle] [nvarchar](150) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [RighthandImage] [nvarchar](250) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [IsMicrosite] [bit] NOT NULL CONSTRAINT [DF_ContentPage_IsMicrosite]  DEFAULT ((0)),
 CONSTRAINT [PK_ContentPage] PRIMARY KEY CLUSTERED 
(
    [PageId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

您的CTE使用内部连接回自身-因此这里存在某种外键关系:

FROM dbo.ContentPage b
JOIN cte ON b.ParentPage = cte.PageId
因此,在
b.ParentPage
上有一个索引,在
PageId
上有另一个索引可能会有所帮助

您的查询也有“<代码> < <代码> B.PytYype < /C> >和<代码>导航< /代码>,因此您应该考虑一个关于<代码> PageType < /C> >的索引(或者可能<代码>(PageType,InNavigation)< /代码>组合)。 此外,您正在按

SortKey
排序,这是基于
PageOrder
的,因此在此基础上的索引可能也很有用


试着一次创建一个索引,重新运行你的查询,比较你的统计数据和数字,然后决定哪些真正对你有利(哪些没有)。索引不是一门精确的科学——你不能总是预测什么有用,什么不有用——你必须尝试一下,并与原始查询进行比较,然后决定什么有用,什么不有用。

一些表说明:ContentPage包含529行,占用2.8Mb,CTE返回约54行数据。这些表是什么样子的(结构、列和数据类型)??有什么类型的索引?有什么类型的索引?WHERE子句中使用的列和索引的外键列?唯一的索引在主键(PageId)上。也只有一个主键,没有外键。谢谢marc,我尝试了几个不同的索引,逻辑读取从4553下降到3297,(PageId的碎片(聚集索引)我会继续尝试你的一些建议。我已经将此标记为已回答,因为索引似乎提高了性能,我还应用于许多其他表。