3

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

Company桌子:

CompanyID     INT                --PRIMARY KEY
CompanyName   NVARCHAR(100)      
CompanyType   INT               --Just can be (1,2,3,4,5,6)     

Position桌子:

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

NONCLUSTERED INDEXCompany桌子上创建了一个:

CREATE NONCLUSTERED INDEX [IX_1] ON [dbo].[Company] 
(
    [CompanyKind] ASC
)
INCLUDE ( [CompanyName]) ON [PRIMARY]
GO

我还在桌子上创建了NONCLUSTERED INDICES两个Position

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 

我的通话声明是这样的:

SET STATISTICS IO ON
DECLARE @return_value int
EXEC    @return_value = [dbo].[spIndexJobList]
        @KeyWord='',
        @WorkExperience = 3,
        @CompanyType = 2,
        @WorkType =1,
        @PageSize = 30,
        @PageNumber =2000

SELECT  'Return Value' = @return_value
GO
SET STATISTICS IO OFF

//------------------------------------------------ ----------------------

(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

//------------------------------------------------ ----------------------

在此处输入图像描述

执行计划提示缺少索引 on(WorkExperience,WorkType)。但是在 (WorkExperience,WorkType) 上创建索引后查询速度较慢。

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

4

4 回答 4

2

DDL:

公司表:

CompanyID     INT NOT NULL PK
CompanyName   NVARCHAR(100) NOT NULL     
CompanyType   TINYINT NOT NULL    

职位表:

PositionID       INT NOT NULL PK
PositionName     NVARCHAR(100) NOT NULL   
CompanyID        INT NOT NULL
WorkExperience   TINYINT NOT NULL
WorkType         TINYINT NOT NULL
CreateTime       SMALLDATETIME
UpdateTime       SMALLDATETIME

指数:

CREATE NONCLUSTERED INDEX IX_Position
     ON Position (WorkExperience, WorkType, PositionName)
     INCLUDE (UpdateTime)

SP:

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 

手动的:

于 2013-07-18T05:32:09.403 回答
0

我会像这样在 Position 上创建一个非聚集索引:

CREATE NONCLUSTERED INDEX IX_Position_WorkExperienceWorkTypePositionName 
ON Position (WorkExperience, WorkType, PositionName)
INCLUDE (PositionID, UpdateTime)
于 2013-07-18T03:23:03.503 回答
0

我还将在 Company 上创建另一个非聚集索引,如下所示:

CREATE NONCLUSTERED INDEX IX_Company_CompanyId_Type
ON Company(CompanyId,CompanyType)

因为where子句中包含“C.CompanyType=@CompanyType”,没有这个索引,这种情况导致了表扫描Company。有了这个索引,它就是索引查找。

于 2013-07-18T05:50:08.520 回答
0

Company.CompanyID 和 Position.CompanyID 应该被索引,您不妨利用 CLUSTER 索引这两个列,以便行在物理上与其索引同步排序。这应该提供显着的性能改进。

于 2013-07-18T06:06:13.653 回答