Sql server 如何改进此sql查询性能?

Sql server 如何改进此sql查询性能?,sql-server,sql-server-2008,Sql Server,Sql Server 2008,假设我有两个表Company(近60K条记录)和Position(近600K条记录) 公司表格: CompanyID INT --PRIMARY KEY CompanyName NVARCHAR(100) CompanyType INT --Just can be (1,2,3,4,5,6) PositionID INT --Primary key Positio

假设我有两个表
Company
(近60K条记录)和
Position
(近600K条记录)

公司
表格:

CompanyID     INT                --PRIMARY KEY
CompanyName   NVARCHAR(100)      
CompanyType   INT               --Just can be (1,2,3,4,5,6)     
PositionID       INT             --Primary key
PositionName     NVARCHAR(100)   
CompanyID        INT             --FK point to Company Table
WorkExperience   INT             --Just can be (1,2,3,4,5,6,7,8) 
WorkType         INT             --Just can be (1,2) 
CreateTime       datetime
UpdateTime       datetime
CREATE NONCLUSTERED INDEX [IX_1] ON [dbo].[Company] 
(
    [CompanyKind] ASC
)
INCLUDE ( [CompanyName]) ON [PRIMARY]
GO
位置
表格:

CompanyID     INT                --PRIMARY KEY
CompanyName   NVARCHAR(100)      
CompanyType   INT               --Just can be (1,2,3,4,5,6)     
PositionID       INT             --Primary key
PositionName     NVARCHAR(100)   
CompanyID        INT             --FK point to Company Table
WorkExperience   INT             --Just can be (1,2,3,4,5,6,7,8) 
WorkType         INT             --Just can be (1,2) 
CreateTime       datetime
UpdateTime       datetime
CREATE NONCLUSTERED INDEX [IX_1] ON [dbo].[Company] 
(
    [CompanyKind] ASC
)
INCLUDE ( [CompanyName]) ON [PRIMARY]
GO
我在
公司
表上创建了一个
非聚集索引

CompanyID     INT                --PRIMARY KEY
CompanyName   NVARCHAR(100)      
CompanyType   INT               --Just can be (1,2,3,4,5,6)     
PositionID       INT             --Primary key
PositionName     NVARCHAR(100)   
CompanyID        INT             --FK point to Company Table
WorkExperience   INT             --Just can be (1,2,3,4,5,6,7,8) 
WorkType         INT             --Just can be (1,2) 
CreateTime       datetime
UpdateTime       datetime
CREATE NONCLUSTERED INDEX [IX_1] ON [dbo].[Company] 
(
    [CompanyKind] ASC
)
INCLUDE ( [CompanyName]) ON [PRIMARY]
GO
我还在
位置
表上创建了两个
非聚集索引

CREATE NONCLUSTERED INDEX [IX_6] ON [dbo].[Position] 
(
    [CompanyID] ASC
)ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IX_8] ON [dbo].[Position] 
(
    [UpdateTime] ASC
) ON [PRIMARY]
我的分页存储过程如下所示:

ALTER PROC [dbo].[spIndexJobList]
    @KeyWord NVARCHAR(50) ,
    @WorkExperience INT ,
    @WorkType INT ,
    @CompanyType INT ,
    @PageSize INT ,
    @PageNumber INT 
    --@RowCount INT OUTPUT
AS 
    DECLARE @RowStart INT
    DECLARE @RowEnd INT
    DECLARE @SQL NVARCHAR(4000)
    DECLARE @ParamDefinition NVARCHAR(2000) 

    SET @SQL = N'SELECT C.CompanyID,C.CompanyName,P.PositionName,P.PositionID,P.UpdateTime, Row_number() OVER (ORDER BY P.UpdateTime DESC) AS RowNumber FROM Company C INNER JOIN Position P ON C.CompanyID=P.CompanyID WHERE 1=1 '
    IF @KeyWord!=''
      SET @SQL = @SQL + ' AND PositionName LIKE @KeyWord'
    IF @WorkExperience !=0 
        SET @SQL = @SQL + ' AND P.WorkExperience=@WorkExperience'
    IF @CompanyType != 0 
        SET @SQL = @SQL + ' AND C.CompanyType=@CompanyType'
    IF @WorkType !=0
        SET @SQL = @SQL + ' AND P.WorkType=@WorkType'
    SET @ParamDefinition = ' @KeyWord    NVarchar(50),
                             @WorkExperience   INT,
                             @WorkType       INT,
                             @CompanyType       INT,
                             @PageSize   INT,
                             @PageNumber INT'
    IF @PageNumber > 0 
        BEGIN
            SET @PageNumber = @PageNumber - 1
            SET @RowStart = @PageSize * @PageNumber + 1 ;
            SET @RowEnd = @RowStart + @PageSize - 1 ;
            SET @SQL = '
        WITH AllJobs
             AS (' + @SQL
                + ')

   SELECT *,(SELECT Count(RowNumber)  FROM   AllJobs) AS TotalRows FROM   AllJobs  WHERE  RowNumber >='
                + STR(@RowStart) + '  AND RowNumber <= ' + STR(@RowEnd) + ''

            EXECUTE sp_Executesql @SQL, @ParamDefinition,
                @KeyWord, @WorkExperience,@WorkType, 
                @CompanyType, @PageSize, @PageNumber

        END 
//-----------------------------------------------------------------------

(30 row(s) affected)
Table 'Company'. Scan count 3, logical reads 632, physical reads 0
Table 'Position'. Scan count 3, logical reads 4865, physical reads 0
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0
//-----------------------------------------------------------------------

(30 row(s) affected)
Table 'Company'. Scan count 3, logical reads 632, physical reads 0
Table 'Position'. Scan count 3, logical reads 4865, physical reads 0
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0

执行计划提示缺少上的索引(工作经验、工作类型)。 但在(工作经验、工作类型)查询上创建索引后速度较慢


任何人给我一些建议都将非常感激。对不起,我的英语不好

我会在位置上创建一个非聚集索引,如下所示:

CREATE NONCLUSTERED INDEX IX_Position_WorkExperienceWorkTypePositionName 
ON Position (WorkExperience, WorkType, PositionName)
INCLUDE (PositionID, UpdateTime)
DDL:

CREATE NONCLUSTERED INDEX IX_Position
     ON Position (WorkExperience, WorkType, PositionName)
     INCLUDE (UpdateTime)
ALTER PROC [dbo].[spIndexJobList]

      @KeyWord NVARCHAR(50) 
    , @WorkExperience TINYINT 
    , @WorkType TINYINT 
    , @CompanyType INT 
    , @PageSize INT 
    , @PageNumber INT 

AS BEGIN

     SET NOCOUNT ON;

     IF @PageNumber > 0 BEGIN

          DECLARE 
                 @RowStart INT
               , @RowEnd INT
               , @SQL NVARCHAR(4000)
               , @ParamDefinition NVARCHAR(500) 

          SELECT @SQL = N'
               SELECT 
                      c.CompanyID
                    , c.CompanyName
                    , p.PositionName
                    , p.PositionID
                    , p.UpdateTime
                    , RowNumber = ROW_NUMBER() OVER (ORDER BY p.UpdateTime DESC)  
               FROM dbo.Company c 
               JOIN dbo.Position p ON c.CompanyID = p.CompanyID 
               WHERE 1=1 '
               + CASE WHEN @KeyWord != '' THEN ' AND PositionName LIKE @KeyWord' ELSE '' END
               + CASE WHEN @WorkExperience != 0 THEN ' AND p.WorkExperience = @WorkExperience' ELSE '' END
               + CASE WHEN @CompanyType != 0 THEN ' AND c.CompanyType = @CompanyType' ELSE '' END
               + CASE WHEN @WorkType != 0 THEN ' AND p.WorkType = @WorkType' ELSE '' END

          SET @ParamDefinition = '@KeyWord NVARCHAR(50),
                                  @WorkExperience INT,
                                  @WorkType INT,
                                  @CompanyType INT,
                                  @PageSize INT,
                                  @PageNumber INT'

          SELECT 
                 @PageNumber = @PageNumber - 1
               , @RowStart = @PageSize * @PageNumber + 1
               , @RowEnd = @RowStart + @PageSize - 1
               , @SQL = '
          WITH AllJobs AS (' + @SQL + ')
          SELECT *
          FROM AllJobs a
          CROSS JOIN (
               SELECT TotalRows = Count(RowNumber)  
               FROM AllJobs
          ) t
          WHERE a.RowNumber BETWEEN ' + STR(@RowStart) + ' AND ' + STR(@RowEnd)

          EXEC sys.sp_executesql 
               @SQL, 
               @ParamDefinition,
               @KeyWord, 
               @WorkExperience,
               @WorkType, 
               @CompanyType, 
               @PageSize, 
               @PageNumber

     END

END 
公司表:

CREATE NONCLUSTERED INDEX IX_Position
     ON Position (WorkExperience, WorkType, PositionName)
     INCLUDE (UpdateTime)
ALTER PROC [dbo].[spIndexJobList]

      @KeyWord NVARCHAR(50) 
    , @WorkExperience TINYINT 
    , @WorkType TINYINT 
    , @CompanyType INT 
    , @PageSize INT 
    , @PageNumber INT 

AS BEGIN

     SET NOCOUNT ON;

     IF @PageNumber > 0 BEGIN

          DECLARE 
                 @RowStart INT
               , @RowEnd INT
               , @SQL NVARCHAR(4000)
               , @ParamDefinition NVARCHAR(500) 

          SELECT @SQL = N'
               SELECT 
                      c.CompanyID
                    , c.CompanyName
                    , p.PositionName
                    , p.PositionID
                    , p.UpdateTime
                    , RowNumber = ROW_NUMBER() OVER (ORDER BY p.UpdateTime DESC)  
               FROM dbo.Company c 
               JOIN dbo.Position p ON c.CompanyID = p.CompanyID 
               WHERE 1=1 '
               + CASE WHEN @KeyWord != '' THEN ' AND PositionName LIKE @KeyWord' ELSE '' END
               + CASE WHEN @WorkExperience != 0 THEN ' AND p.WorkExperience = @WorkExperience' ELSE '' END
               + CASE WHEN @CompanyType != 0 THEN ' AND c.CompanyType = @CompanyType' ELSE '' END
               + CASE WHEN @WorkType != 0 THEN ' AND p.WorkType = @WorkType' ELSE '' END

          SET @ParamDefinition = '@KeyWord NVARCHAR(50),
                                  @WorkExperience INT,
                                  @WorkType INT,
                                  @CompanyType INT,
                                  @PageSize INT,
                                  @PageNumber INT'

          SELECT 
                 @PageNumber = @PageNumber - 1
               , @RowStart = @PageSize * @PageNumber + 1
               , @RowEnd = @RowStart + @PageSize - 1
               , @SQL = '
          WITH AllJobs AS (' + @SQL + ')
          SELECT *
          FROM AllJobs a
          CROSS JOIN (
               SELECT TotalRows = Count(RowNumber)  
               FROM AllJobs
          ) t
          WHERE a.RowNumber BETWEEN ' + STR(@RowStart) + ' AND ' + STR(@RowEnd)

          EXEC sys.sp_executesql 
               @SQL, 
               @ParamDefinition,
               @KeyWord, 
               @WorkExperience,
               @WorkType, 
               @CompanyType, 
               @PageSize, 
               @PageNumber

     END

END 
职位表:

CREATE NONCLUSTERED INDEX IX_Position
     ON Position (WorkExperience, WorkType, PositionName)
     INCLUDE (UpdateTime)
ALTER PROC [dbo].[spIndexJobList]

      @KeyWord NVARCHAR(50) 
    , @WorkExperience TINYINT 
    , @WorkType TINYINT 
    , @CompanyType INT 
    , @PageSize INT 
    , @PageNumber INT 

AS BEGIN

     SET NOCOUNT ON;

     IF @PageNumber > 0 BEGIN

          DECLARE 
                 @RowStart INT
               , @RowEnd INT
               , @SQL NVARCHAR(4000)
               , @ParamDefinition NVARCHAR(500) 

          SELECT @SQL = N'
               SELECT 
                      c.CompanyID
                    , c.CompanyName
                    , p.PositionName
                    , p.PositionID
                    , p.UpdateTime
                    , RowNumber = ROW_NUMBER() OVER (ORDER BY p.UpdateTime DESC)  
               FROM dbo.Company c 
               JOIN dbo.Position p ON c.CompanyID = p.CompanyID 
               WHERE 1=1 '
               + CASE WHEN @KeyWord != '' THEN ' AND PositionName LIKE @KeyWord' ELSE '' END
               + CASE WHEN @WorkExperience != 0 THEN ' AND p.WorkExperience = @WorkExperience' ELSE '' END
               + CASE WHEN @CompanyType != 0 THEN ' AND c.CompanyType = @CompanyType' ELSE '' END
               + CASE WHEN @WorkType != 0 THEN ' AND p.WorkType = @WorkType' ELSE '' END

          SET @ParamDefinition = '@KeyWord NVARCHAR(50),
                                  @WorkExperience INT,
                                  @WorkType INT,
                                  @CompanyType INT,
                                  @PageSize INT,
                                  @PageNumber INT'

          SELECT 
                 @PageNumber = @PageNumber - 1
               , @RowStart = @PageSize * @PageNumber + 1
               , @RowEnd = @RowStart + @PageSize - 1
               , @SQL = '
          WITH AllJobs AS (' + @SQL + ')
          SELECT *
          FROM AllJobs a
          CROSS JOIN (
               SELECT TotalRows = Count(RowNumber)  
               FROM AllJobs
          ) t
          WHERE a.RowNumber BETWEEN ' + STR(@RowStart) + ' AND ' + STR(@RowEnd)

          EXEC sys.sp_executesql 
               @SQL, 
               @ParamDefinition,
               @KeyWord, 
               @WorkExperience,
               @WorkType, 
               @CompanyType, 
               @PageSize, 
               @PageNumber

     END

END 
索引:

CREATE NONCLUSTERED INDEX IX_Position
     ON Position (WorkExperience, WorkType, PositionName)
     INCLUDE (UpdateTime)
ALTER PROC [dbo].[spIndexJobList]

      @KeyWord NVARCHAR(50) 
    , @WorkExperience TINYINT 
    , @WorkType TINYINT 
    , @CompanyType INT 
    , @PageSize INT 
    , @PageNumber INT 

AS BEGIN

     SET NOCOUNT ON;

     IF @PageNumber > 0 BEGIN

          DECLARE 
                 @RowStart INT
               , @RowEnd INT
               , @SQL NVARCHAR(4000)
               , @ParamDefinition NVARCHAR(500) 

          SELECT @SQL = N'
               SELECT 
                      c.CompanyID
                    , c.CompanyName
                    , p.PositionName
                    , p.PositionID
                    , p.UpdateTime
                    , RowNumber = ROW_NUMBER() OVER (ORDER BY p.UpdateTime DESC)  
               FROM dbo.Company c 
               JOIN dbo.Position p ON c.CompanyID = p.CompanyID 
               WHERE 1=1 '
               + CASE WHEN @KeyWord != '' THEN ' AND PositionName LIKE @KeyWord' ELSE '' END
               + CASE WHEN @WorkExperience != 0 THEN ' AND p.WorkExperience = @WorkExperience' ELSE '' END
               + CASE WHEN @CompanyType != 0 THEN ' AND c.CompanyType = @CompanyType' ELSE '' END
               + CASE WHEN @WorkType != 0 THEN ' AND p.WorkType = @WorkType' ELSE '' END

          SET @ParamDefinition = '@KeyWord NVARCHAR(50),
                                  @WorkExperience INT,
                                  @WorkType INT,
                                  @CompanyType INT,
                                  @PageSize INT,
                                  @PageNumber INT'

          SELECT 
                 @PageNumber = @PageNumber - 1
               , @RowStart = @PageSize * @PageNumber + 1
               , @RowEnd = @RowStart + @PageSize - 1
               , @SQL = '
          WITH AllJobs AS (' + @SQL + ')
          SELECT *
          FROM AllJobs a
          CROSS JOIN (
               SELECT TotalRows = Count(RowNumber)  
               FROM AllJobs
          ) t
          WHERE a.RowNumber BETWEEN ' + STR(@RowStart) + ' AND ' + STR(@RowEnd)

          EXEC sys.sp_executesql 
               @SQL, 
               @ParamDefinition,
               @KeyWord, 
               @WorkExperience,
               @WorkType, 
               @CompanyType, 
               @PageSize, 
               @PageNumber

     END

END 
SP:

CREATE NONCLUSTERED INDEX IX_Position
     ON Position (WorkExperience, WorkType, PositionName)
     INCLUDE (UpdateTime)
ALTER PROC [dbo].[spIndexJobList]

      @KeyWord NVARCHAR(50) 
    , @WorkExperience TINYINT 
    , @WorkType TINYINT 
    , @CompanyType INT 
    , @PageSize INT 
    , @PageNumber INT 

AS BEGIN

     SET NOCOUNT ON;

     IF @PageNumber > 0 BEGIN

          DECLARE 
                 @RowStart INT
               , @RowEnd INT
               , @SQL NVARCHAR(4000)
               , @ParamDefinition NVARCHAR(500) 

          SELECT @SQL = N'
               SELECT 
                      c.CompanyID
                    , c.CompanyName
                    , p.PositionName
                    , p.PositionID
                    , p.UpdateTime
                    , RowNumber = ROW_NUMBER() OVER (ORDER BY p.UpdateTime DESC)  
               FROM dbo.Company c 
               JOIN dbo.Position p ON c.CompanyID = p.CompanyID 
               WHERE 1=1 '
               + CASE WHEN @KeyWord != '' THEN ' AND PositionName LIKE @KeyWord' ELSE '' END
               + CASE WHEN @WorkExperience != 0 THEN ' AND p.WorkExperience = @WorkExperience' ELSE '' END
               + CASE WHEN @CompanyType != 0 THEN ' AND c.CompanyType = @CompanyType' ELSE '' END
               + CASE WHEN @WorkType != 0 THEN ' AND p.WorkType = @WorkType' ELSE '' END

          SET @ParamDefinition = '@KeyWord NVARCHAR(50),
                                  @WorkExperience INT,
                                  @WorkType INT,
                                  @CompanyType INT,
                                  @PageSize INT,
                                  @PageNumber INT'

          SELECT 
                 @PageNumber = @PageNumber - 1
               , @RowStart = @PageSize * @PageNumber + 1
               , @RowEnd = @RowStart + @PageSize - 1
               , @SQL = '
          WITH AllJobs AS (' + @SQL + ')
          SELECT *
          FROM AllJobs a
          CROSS JOIN (
               SELECT TotalRows = Count(RowNumber)  
               FROM AllJobs
          ) t
          WHERE a.RowNumber BETWEEN ' + STR(@RowStart) + ' AND ' + STR(@RowEnd)

          EXEC sys.sp_executesql 
               @SQL, 
               @ParamDefinition,
               @KeyWord, 
               @WorkExperience,
               @WorkType, 
               @CompanyType, 
               @PageSize, 
               @PageNumber

     END

END 
手册:

CREATE NONCLUSTERED INDEX IX_Position
     ON Position (WorkExperience, WorkType, PositionName)
     INCLUDE (UpdateTime)
ALTER PROC [dbo].[spIndexJobList]

      @KeyWord NVARCHAR(50) 
    , @WorkExperience TINYINT 
    , @WorkType TINYINT 
    , @CompanyType INT 
    , @PageSize INT 
    , @PageNumber INT 

AS BEGIN

     SET NOCOUNT ON;

     IF @PageNumber > 0 BEGIN

          DECLARE 
                 @RowStart INT
               , @RowEnd INT
               , @SQL NVARCHAR(4000)
               , @ParamDefinition NVARCHAR(500) 

          SELECT @SQL = N'
               SELECT 
                      c.CompanyID
                    , c.CompanyName
                    , p.PositionName
                    , p.PositionID
                    , p.UpdateTime
                    , RowNumber = ROW_NUMBER() OVER (ORDER BY p.UpdateTime DESC)  
               FROM dbo.Company c 
               JOIN dbo.Position p ON c.CompanyID = p.CompanyID 
               WHERE 1=1 '
               + CASE WHEN @KeyWord != '' THEN ' AND PositionName LIKE @KeyWord' ELSE '' END
               + CASE WHEN @WorkExperience != 0 THEN ' AND p.WorkExperience = @WorkExperience' ELSE '' END
               + CASE WHEN @CompanyType != 0 THEN ' AND c.CompanyType = @CompanyType' ELSE '' END
               + CASE WHEN @WorkType != 0 THEN ' AND p.WorkType = @WorkType' ELSE '' END

          SET @ParamDefinition = '@KeyWord NVARCHAR(50),
                                  @WorkExperience INT,
                                  @WorkType INT,
                                  @CompanyType INT,
                                  @PageSize INT,
                                  @PageNumber INT'

          SELECT 
                 @PageNumber = @PageNumber - 1
               , @RowStart = @PageSize * @PageNumber + 1
               , @RowEnd = @RowStart + @PageSize - 1
               , @SQL = '
          WITH AllJobs AS (' + @SQL + ')
          SELECT *
          FROM AllJobs a
          CROSS JOIN (
               SELECT TotalRows = Count(RowNumber)  
               FROM AllJobs
          ) t
          WHERE a.RowNumber BETWEEN ' + STR(@RowStart) + ' AND ' + STR(@RowEnd)

          EXEC sys.sp_executesql 
               @SQL, 
               @ParamDefinition,
               @KeyWord, 
               @WorkExperience,
               @WorkType, 
               @CompanyType, 
               @PageSize, 
               @PageNumber

     END

END 

    • 此外,我还将在公司上创建另一个非聚集索引,如下所示:

      CREATE NONCLUSTERED INDEX IX_Company_CompanyId_Type
      ON Company(CompanyId,CompanyType)
      
      因为where子句包含“C.CompanyType=@CompanyType”,没有这个索引,这个条件导致表扫描公司。
      有了这个索引,它就是索引搜索

      Company.CompanyID和Position.CompanyID应该被索引,您还可以利用对这两列的集群索引,使行的物理顺序与其索引同步。这将提供显著的性能改进

      @StuartAinsworth感谢您的帮助。您的索引结果如下:(30行受影响)表“公司”。扫描计数0,逻辑读取600226,物理读取0,预读0,lob逻辑读取0,lob物理读取0,lob预读0。表“位置”。扫描计数2,逻辑读取1802168,物理读取0您可以提供有关节点“聚集索引扫描”的更多信息吗?该节点的成本为32%?以及“密钥查找”节点(成本为19%),一个可能的性能提升可能是不使用动态SQL。