Sql server SQL Server:如何提高WHERE子句中具有多个CTE和子查询的查询的性能

Sql server SQL Server:如何提高WHERE子句中具有多个CTE和子查询的查询的性能,sql-server,sqlperformance,Sql Server,Sqlperformance,我有以下两个表格: CREATE TABLE Portfolio.DailyPortfolio ( BbgID varchar(30) NOT NULL, Ticker varchar(22) NULL, Cusip char(9) NULL, SecurityDescription varchar(50) NOT NULL, AssetCategory varchar(25) NOT NULL, LSPosition char(3

我有以下两个表格:

    CREATE TABLE Portfolio.DailyPortfolio
    (
    BbgID varchar(30) NOT NULL,
    Ticker varchar(22) NULL,
    Cusip char(9) NULL,
    SecurityDescription varchar(50) NOT NULL,
    AssetCategory varchar(25) NOT NULL,
    LSPosition char(3) NULL,
    Ccy varchar(25) NOT NULL,
    Quantity int NULL,
    AvgCost decimal(7,3) NULL,
    PriceLocal decimal(7,3) NULL,
    Cost int NULL,
    MktValNet int NULL,
    GLPeriod int NULL,
    Beta decimal(4,2) NULL,
    BetaExpNet int NULL,
    BetaExpGross int NULL,
    Delta decimal(4,2) NULL,
    DeltaExpNet int NULL,
    DeltaExpGross int NULL,
    Issuer varchar(48) NOT NULL,
    Country varchar(30) NOT NULL,
    Region varchar(20) NOT NULL,
    Sector varchar(30) NOT NULL,
    Industry varchar(48) NOT NULL,
    MktCapCategory varchar(24) NULL,
    MktCapEnd int NULL,
    Date date NOT NULL,
    PortfolioID  AS BbgID+LSPosition+ Convert(varchar(8),Date,112) Persisted Primary Key
    )
    GO
这是第二张表:

    CREATE TABLE Portfolio.DailyStats
    (
    Date date NOT NULL Primary Key,
    NAV int NOT NULL,
    SP500 decimal(8,4) NULL,
    R2K decimal(8,4) NULL,
    NetExp decimal(8,4) NULL,
    GrossExp decimal(8,4) NULL,
    )
    GO
    ALTER TABLE Portfolio.DailyStats
    ADD [YrMn] as  CONVERT(varchar(7), Date)
    GO
每天将80-100行添加到DailyPortfolio表中(该表当前约有32000行)。每个工作日向DailyStats表中添加1行(当前约有500行)。Daily Portfolio表中的Date列与DailyStats表中的Date列具有外键关系

我必须创建一个视图,其中包含两个表中的一些列,并使用last quarter作为日期范围。该视图的最后一列在其计算中使用了NAV列的平均值,其中平均值是通过在季度中3个月的每个月的第一天使用NAV计算的。以下是视图的DDL:

    CREATE VIEW Portfolio.PNLLastQTD
    AS
    WITH CTE1
    AS
    (
    Select Date, NAV,YrMn, ROW_NUMBER() OVER (PARTITION BY YrMn ORDER BY Date) AS Row
    FROM Portfolio.DailyStats

    WHERE DATE BETWEEN 
        (SELECT Convert(date, DATEADD(q, DATEDIFF(q,0,GETDATE()) -1 ,0)))
    AND
        (SELECT Convert(date, DATEADD(s,-1,DATEADD(q, DATEDIFF(q,0,GETDATE()),0))))
    ),
    CTE2
    AS
    ( 
    SELECT  AvG (NAV) As AvgNAV
    FROM CTE1
    WHERE Row=1
    )
    SELECT IssuerLS, Issuer, Ticker,  SUM (GLPeriod) As [PNL],
        CAST(SUM(GLPeriod)As Decimal (13,2)) /  CAST(CTE2.[AvgNAV] As Decimal (13,2)) as [%ofNAV]
    FROM Portfolio.DailyPortfolioIssuerLS ls
    JOIN cte2 on 1=1
    WHERE ReportDate 
    BETWEEN 
        (SELECT Convert(date, DATEADD(q, DATEDIFF(q,0,GETDATE()) -1 ,0)))
    AND
        (SELECT Convert(date, DATEADD(s,-1,DATEADD(q, DATEDIFF(q,0,GETDATE()),0))))
    GROUP BY 
        Issuer, Ticker, IssuerLS, CTE2.[AvgNAV]
    GO
视图工作正常,但执行几乎需要20秒!我这里有几个问题:

  • 是否应该对视图的DDL进行一些更改
  • 在DailyPortfolio表的日期列(如果可能的话)上创建非聚集索引是一个好主意吗
  • 对于这个特定的问题,我还应该考虑其他什么来提高查询性能吗

  • 谢谢你的帮助。请原谅明显的错误,因为我是SQL新手。

    我想结束这个问题的循环。这里我需要做的是创建两个非聚集索引。我使用了以下步骤:

  • 将我的查询放在查询窗口上
  • 单击工具箱上的“显示估计执行计划”按钮,立即通知我缺少非集群索引
  • 创建了第一个非聚集索引:

    USE [OurDB]
    GO
    CREATE NONCLUSTERED INDEX NCI_DailyPort_Issuer_Date
    ON [Portfolio].[DailyPortfolio] ([Issuer],[Date])
    GO   
    
  • 重复步骤2并按照建议创建第二个非聚集索引:

    USE [OurDB]
    GO
    CREATE NONCLUSTERED INDEX NCI_DailyPort_Date_INC_DexpN_Issuer
    ON [Portfolio].[DailyPortfolio] ([Date])
    INCLUDE ([DeltaExpNet],[Issuer])
    GO    
    
  • 现在执行查询所需的时间不到3秒,比之前的24秒要好得多


    注意:如果右键单击通知您缺少索引的行,您可以选择一个选项来查看索引的代码,这样可以节省您的时间。

    Id将此发布在dba.stackexchange.com和codereview.stackexchange.com上,尽管您也可以在此处找到有用的答案。您可能可以通过对查询中涉及的表使用适当的索引来提高性能。分析SSMS中的执行计划,可能会提出一些建议。