2013-07-18 46 views
3

比方說,我有兩個表Company(幾乎60K記錄)和Position(近60萬條記錄)如何提高這個sql查詢性能?

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 ON的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 
    [email protected] 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 [email protected]' 
    IF @CompanyType != 0 
     SET @SQL = @SQL + ' AND [email protected]' 
    IF @WorkType !=0 
     SET @SQL = @SQL + ' AND [email protected]' 
    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)查詢速度較慢。

任何人給我的一些建議將非常感激。對不起,我的英語不好!

+0

您能否提供關於節點「聚集索引掃描」的更多信息,其成本爲32%?以及成本19%的「密鑰查找」節點。 – yaoxing

+0

可能的性能提升可能不是使用動態SQL。 – Alexander

回答

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 

手冊:

http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/12/bad-habits-to-kick-using-the-wrong-data-type.aspx

+0

@ Devart-感謝您的幫助! – user441222

+0

不客氣@ user441222 :) – Devart

0

我將在當前位置創建一個非聚集索引,像這樣:

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

@ StuartAinsworth - 感謝您的幫助。您的索引結果如下: (30行受影響) 表'公司'。掃描計數0,邏輯讀取600226,物理讀取0,預讀讀取0,lob邏輯讀取0,lob物理讀取0,lob預讀讀取0. 表'位置'。掃描計數2,邏輯讀取1802168,物理讀取0 – user441222

0

另外我想在公司創建另一個非聚集索引象下面這樣:

CREATE NONCLUSTERED INDEX IX_Company_CompanyId_Type 
ON Company(CompanyId,CompanyType) 

因爲在where子句中包括「[email protected]」,如果沒有這個指標,這種情況引起了表掃描公司。 有了這個索引,它就是索引查找。

0

Company.CompanyID和Position.CompanyID應該被編入索引,並且您還可以利用CLUSTER對這兩列進行索引,以便使這些行在物理上與其索引同步排序。這應該可以顯着提高性能。