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。