如何提高这个sql查询性能?

时间:2013-07-18 02:56:09

标签: sql-server sql-server-2008

假设我有两张表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 INDEX表格上创建了​​Company

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

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

enter image description here

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

任何给我一些建议的人都会非常感激。抱歉我的英文不好!

4 个答案:

答案 0 :(得分: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 

<强>手册

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

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

CREATE NONCLUSTERED INDEX IX_Company_CompanyId_Type
ON Company(CompanyId,CompanyType)

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

答案 3 :(得分:0)

应该对Company.CompanyID和Position.CompanyID建立索引,您也可以利用CLUSTER对这两列进行索引,以便对这些行进行物理排序,使其与索引同步。这应该可以显着提高性能。