EXEC sp_executesql很慢

时间:2017-02-26 15:05:04

标签: sql sql-server sp-executesql

我有一个这样的存储过程:

声明@where nvarchar(max)

set @where=' where 1=1 '
if(@IsSimNha is not null)
    set @where+=' and s.IsSimNha=@IsSimNha'
if(@IsSearchSimPSC is not null)
    set @where+=' and s.HanPhaiPhatSinhLai<=@HanPhaiPhatSinhLai'
if(@GiaTu is not null)
    set @where+=' and s.AgentPrice>=@GiaTu'
if(@GiaDen is not null)
    set @where+=' and s.AgentPrice<=@GiaDen'
if(@AgentID is not null)
    set @where+=' and s.AgentId=@AgentID'
if(@NhaMangId is not null)
    set @where+=' and s.NhaMangId=@NhaMangId'
if(@TinhTrangID is not null)
    set @where+=' and s.StatusId=@TinhTrangID'
if(@NgayNhapTu is not null)
    set @where+=' and s.NgayNhapSim>=@NgayNhapTu'
if(@NgayNhapDen is not null)
    set @where+=' and s.NgayNhapSim<=@NgayNhapDen'

if(@NgayPscTu is not null)
    set @where+=' and s.NgayPhatSinhCuoc>=@NgayPscTu'
if(@NgayPscDen is not null)
    set @where+=' and s.NgayPhatSinhCuoc<=@NgayPscDen'

if(@HanPSCTu is not null)
    set @where+=' and s.HanPhaiPhatSinhLai>=@HanPSCTu'
if(@HanPSCDen is not null)
    set @where+=' and s.HanPhaiPhatSinhLai<=@HanPSCDen'

if(@HanSuDungTu is not null)
    set @where+=' and s.HanSuDung>=@HanSuDungTu'
if(@HanSuDungDen is not null)
    set @where+=' and s.HanSuDung<=@HanSuDungDen'
if(@SoSeri is not null)
    set @where+=' and s.SoSeri<=@SoSeri'
if(@Lenght is not null)
    set @where+=' and LEN(s.Number) = @Lenght'
if(@SearchDau is not null)
    set @where+=' and s.Number like @SearchDau+''%'''
if(@SearchGiua is not null)
    set @where+=' and s.Number like ''%''+@SearchGiua+''%'''
if(@SearchCuoi is not null)
    set @where+=' and s.Number like ''%''+@SearchCuoi'

set @sql = 'declare @TotalItemCount int;'
set @sql+= ' select  @TotalItemCount=count(1)
            from sims s with (NOLOCK) '
            +@where
set @sql+=' select @TotalItemCount TotalItemCount, s.SimId,s.Number, s.DisplayNumber, s.AgentId,ag.Email,ag.Mobile2,s.NhaMangId,s.StatusId,s.SalelPrice,
s.SaleOffPrice,s.Commisions,s.AgentPrice,s.HoaHong,s.IsShow,s.DateCreated,ag.AgentName,s.SoSeri,s.SimTypeId,
s.NgayPhatSinhCuoc,s.HanPhaiPhatSinhLai,s.MaCaNhan,s.SoPhatSinhCuoc,s.HanSuDung,s.GhiChu,s.SoTienCamKet,s.SoThangCamKet,
s.NgayKichHoat, s.NgayNhapSim,s.IsSimNha,s.CoHoTroTraGop,s.GhiChuTraGop,s.ViTriId
from sims s with (NOLOCK) left join Agents ag with (NOLOCK) on s.AgentID=ag.AgentID ' +@where

declare @orderbysql nvarchar(max);

if(@OrderBy='SalelPrice')
begin
    if(@SortBy=1)
        set @orderbysql= N' ORDER BY s.SalelPrice asc '
    else set @orderbysql= N' ORDER BY s.SalelPrice desc '
end
else if(@OrderBy='SaleOffPrice')
begin
    if(@SortBy=1)
        set @orderbysql= N' ORDER BY s.SaleOffPrice asc '
    else set @orderbysql= N' ORDER BY s.SaleOffPrice desc '
end
else if(@OrderBy='AgentPrice')
begin
    if(@SortBy=1)
        set @orderbysql= N' ORDER BY s.AgentPrice asc '
    else set @orderbysql= N' ORDER BY s.AgentPrice desc '
end
else if(@OrderBy='NgayPSC')
begin
    if(@SortBy=1)
        set @orderbysql= N' ORDER BY s.NgayPSC asc '
    else set @orderbysql= N' ORDER BY s.NgayPSC desc '
end
else if(@OrderBy='HanPhatSinhCuoc')
begin
    if(@SortBy=1)
        set @orderbysql= N' ORDER BY s.HanPhatSinhCuoc asc '
    else set @orderbysql= N' ORDER BY s.HanPhatSinhCuoc desc '
end 
else if(@OrderBy='HanSuDung')
begin
    if(@SortBy=1)
        set @orderbysql= N' ORDER BY s.HanSuDung asc '
    else set @orderbysql= N' ORDER BY s.HanSuDung desc '
end 
else if(@OrderBy='NgayNhapSim')
begin
    if(@SortBy=1)
        set @orderbysql= N' ORDER BY s.NgayNhapSim asc '
    else set @orderbysql= N' ORDER BY s.NgayNhapSim desc '
end 
else if(@OrderBy='Number')
begin
    if(@SortBy=1)
        set @orderbysql= N' ORDER BY s.Number asc '
    else set @orderbysql= N' ORDER BY s.Number desc '
end 
else if(@OrderBy='TenDaiLy')
begin
    if(@SortBy=1)
        set @orderbysql= N' ORDER BY s.TenDaiLy asc '
    else set @orderbysql= N' ORDER BY s.TenDaiLy desc '
end 
else if(@OrderBy='SoSeri')
begin
    if(@SortBy=1)
        set @orderbysql= N' ORDER BY s.SoSeri asc '
    else set @orderbysql= N' ORDER BY s.SoSeri desc '
end 
else
begin
    if(@SortBy=1)
    begin
        if(@IsSimNha=1)
            set @orderbysql= N' ORDER BY s.HanPhatSinhCuoc asc '
        else set @orderbysql= N' ORDER BY s.SimId asc '
    end
    else
    begin
        if(@IsSimNha=1)
            set @orderbysql= N' ORDER BY s.HanPhatSinhCuoc desc '
        else set @orderbysql= N' ORDER BY s.SimId desc '
    end

end
set @orderbysql+=' OFFSET (@PageNum-1)* @PageSize ROWS FETCH NEXT @PageSize ROWS ONLY'
set @sql+=@orderbysql

print @sql
EXEC sp_executesql @sql,N'@IsSimNha bit,@IsSearchSimPSC bit, @HanPhaiPhatSinhLai datetime,@GiaTu decimal(18,0),@GiaDen decimal(18,0),@NhaMangId int,@AgentID int,
@TinhTrangID int,@NgayNhapTu datetime,@NgayNhapDen datetime,@NgayPscTu datetime,@NgayPscDen datetime,@HanPSCTu datetime,@HanPSCDen datetime,@HanSuDungTu datetime,
@HanSuDungDen datetime,@SoSeri nvarchar(30),@Lenght int,@SearchDau nvarchar(30),@SearchGiua nvarchar(30),@SearchCuoi nvarchar(30),@PageNum int,@PageSize int ',@IsSimNha ,@IsSearchSimPSC , @HanPhaiPhatSinhLai ,@GiaTu ,@GiaDen,@NhaMangId ,@AgentID ,
@TinhTrangID ,@NgayNhapTu ,@NgayNhapDen ,@NgayPscTu ,@NgayPscDen ,@HanPSCTu ,@HanPSCDen ,@HanSuDungTu ,
@HanSuDungDen ,@SoSeri ,@Lenght ,@SearchDau ,@SearchGiua ,@SearchCuoi,@PageNum,@PageSize

完成时间超过3秒。

但是当我把脚本结果运行时:

select 
    @TotalItemCount TotalItemCount, s.SimId,s.Number, s.DisplayNumber, 
    s.AgentId, ag.Email, ag.Mobile2, s.NhaMangId, s.StatusId, s.SalelPrice,
    s.SaleOffPrice, s.Commisions, s.AgentPrice, s.HoaHong, s.IsShow, 
    s.DateCreated, ag.AgentName, s.SoSeri, s.SimTypeId,
    s.NgayPhatSinhCuoc, s.HanPhaiPhatSinhLai, s.MaCaNhan, s.SoPhatSinhCuoc, 
    s.HanSuDung, s.GhiChu, s.SoTienCamKet, s.SoThangCamKet,
    s.NgayKichHoat, s.NgayNhapSim, s.IsSimNha, s.CoHoTroTraGop, 
    s.GhiChuTraGop, s.ViTriId
from 
    sims s with (NOLOCK) 
left join 
    Agents ag with (NOLOCK) on s.AgentID = ag.AgentID 
where  
    s.Number like '0973688639'+'%' 
order by
    s.SimId desc  
    OFFSET 0 ROWS FETCH NEXT 50 ROWS ONLY

并且运行,它只需要0.02s

我不知道为什么这么慢。

注意:@sql variable =第二个脚本。

有人可以帮助我吗?

全部谢谢

2 个答案:

答案 0 :(得分:0)

三件事:

  1. 添加option (recompile)
  2. 使用DMV
  3. 获取sims中所有行的计数
  4. 看起来你只是从Agents表中提取ag.Email,ag.Mobile2,如果它没有返回超过1行(只有1或0行),那么你可以尝试使用替代模式{ {1}}在此处描述:Pagination with offset / fetch : A better way - Aaron Bertrand
  5. 1)offset ... fetch

    这一行之后:

    option (recompile)

    添加以下行:

    set @sql+=@orderbysql ..
    

    2)使用DMV获取表格的行数。

    换掉这个:

    set @sql+= ' option (recompile);';
    

    为此:

    ...
    
    set @sql = 'declare @TotalItemCount int;'
    set @sql+= ' select  @TotalItemCount=count(1)
                from sims s with (NOLOCK) '
                +@where
    set @sql+=' select @TotalItemCount TotalItemCount, s.SimId,s.Number, s.DisplayNumber, s.AgentId,ag.Email,ag.Mobile2,s.NhaMangId,s.StatusId,s.SalelPrice,
    s.SaleOffPrice,s.Commisions,s.AgentPrice,s.HoaHong,s.IsShow,s.DateCreated,ag.AgentName,s.SoSeri,s.SimTypeId,
    s.NgayPhatSinhCuoc,s.HanPhaiPhatSinhLai,s.MaCaNhan,s.SoPhatSinhCuoc,s.HanSuDung,s.GhiChu,s.SoTienCamKet,s.SoThangCamKet,
    s.NgayKichHoat, s.NgayNhapSim,s.IsSimNha,s.CoHoTroTraGop,s.GhiChuTraGop,s.ViTriId
    from sims s with (NOLOCK) left join Agents ag with (NOLOCK) on s.AgentID=ag.AgentID ' +@where
    
    ...
    
    EXEC sp_executesql @sql,N'@IsSimNha bit,@IsSearchSimPSC bit, @HanPhaiPhatSinhLai datetime,@GiaTu decimal(18,0),@GiaDen decimal(18,0),@NhaMangId int,@AgentID int,
    @TinhTrangID int,@NgayNhapTu datetime,@NgayNhapDen datetime,@NgayPscTu datetime,@NgayPscDen datetime,@HanPSCTu datetime,@HanPSCDen datetime,@HanSuDungTu datetime,
    @HanSuDungDen datetime,@SoSeri nvarchar(30),@Lenght int,@SearchDau nvarchar(30),@SearchGiua nvarchar(30),@SearchCuoi nvarchar(30),@PageNum int,@PageSize int ',@IsSimNha ,@IsSearchSimPSC , @HanPhaiPhatSinhLai ,@GiaTu ,@GiaDen,@NhaMangId ,@AgentID ,
    @TinhTrangID ,@NgayNhapTu ,@NgayNhapDen ,@NgayPscTu ,@NgayPscDen ,@HanPSCTu ,@HanPSCDen ,@HanSuDungTu ,
    @HanSuDungDen ,@SoSeri ,@Lenght ,@SearchDau ,@SearchGiua ,@SearchCuoi,@PageNum,@PageSize
    

    3)使用此处描述的... declare @TotalItemCount int; select @TotalItemCount=p.rows from sys.indexes i inner join sys.partitions p on p.object_id = i.object_id and p.index_id = i.index_id where i.object_id = object_id(N'dbo.sims') and i.index_id < 2; set @sql=' select @TotalItemCount as TotalItemCount, s.SimId,s.Number, s.DisplayNumber, s.AgentId,ag.Email,ag.Mobile2,s.NhaMangId,s.StatusId,s.SalelPrice, s.SaleOffPrice,s.Commisions,s.AgentPrice,s.HoaHong,s.IsShow,s.DateCreated,ag.AgentName,s.SoSeri,s.SimTypeId, s.NgayPhatSinhCuoc,s.HanPhaiPhatSinhLai,s.MaCaNhan,s.SoPhatSinhCuoc,s.HanSuDung,s.GhiChu,s.SoTienCamKet,s.SoThangCamKet, s.NgayKichHoat, s.NgayNhapSim,s.IsSimNha,s.CoHoTroTraGop,s.GhiChuTraGop,s.ViTriId from sims s with (NOLOCK) left join Agents ag with (NOLOCK) on s.AgentID=ag.AgentID ' +@where ... EXEC sp_executesql @sql ,N'@IsSimNha bit,@IsSearchSimPSC bit, @HanPhaiPhatSinhLai datetime,@GiaTu decimal(18,0),@GiaDen decimal(18,0),@NhaMangId int,@AgentID int, @TinhTrangID int,@NgayNhapTu datetime,@NgayNhapDen datetime,@NgayPscTu datetime,@NgayPscDen datetime,@HanPSCTu datetime,@HanPSCDen datetime,@HanSuDungTu datetime, @HanSuDungDen datetime,@SoSeri nvarchar(30),@Lenght int,@SearchDau nvarchar(30),@SearchGiua nvarchar(30),@SearchCuoi nvarchar(30),@PageNum int,@PageSize int, @TotalItemCount bigint' ,@IsSimNha ,@IsSearchSimPSC , @HanPhaiPhatSinhLai ,@GiaTu ,@GiaDen,@NhaMangId ,@AgentID , @TinhTrangID ,@NgayNhapTu ,@NgayNhapDen ,@NgayPscTu ,@NgayPscDen ,@HanPSCTu ,@HanPSCDen ,@HanSuDungTu , @HanSuDungDen ,@SoSeri ,@Lenght ,@SearchDau ,@SearchGiua ,@SearchCuoi,@PageNum,@PageSize,@TotalItemCount 的替代模式:Pagination with offset / fetch : A better way - Aaron Bertrand

    目标是重新组织动态sql以此模式而不是当前模式生成查询:

    这将需要对当前代码进行最多重构,因此如果前两个更改没有帮助,则值得测试:。

    offset ... fetch

答案 1 :(得分:0)

我建议你仔细研究一下你的数据类型,特别是nvarchar,我回想一下使用索引扫描而不是索引搜索的执行计划的多个问题只是因为数据类型与你的索引不匹配。

EG(ASP.NET C#):

SqlCommand command = new SqlCommand();
command.CommandText = "SELECT [COLUMN2] FROM [TABLE] WHERE COLUMN1 = @value";
command.Parameters.AddWithValue("@value", orderNumber);


exec sp_executesql N'SELECT [COLUMN2] FROM [TABLE] WHERE COLUMN1 = @Value',N'@Value nvarchar(32)',@Value=N'b12af2381c8a40e7aaf6f682e209b2ed' 

这是错误的,因为我们的表使用varchar [32]作为COLUMN1,这默认生成一个NVARCHAR [32]类型的查询。正确的方法是指定类型:

SqlCommand command = new SqlCommand();
command.CommandText = "SELECT [COLUMN2] FROM [TABLE] WHERE COLUMN1 = @value";
command.Parameters.Add("@value", SqlDbType.VarChar, 32);
command.Parameters["@value"].Value = orderNumber; enter code here


exec sp_executesql N'SELECT [COLUMN2] FROM [TABLE] WHERE COLUMN1 = @Value',N'@Value varchar(32)',@Value=N'b12af2381c8a40e7aaf6f682e209b2ed'

不管你信不信,这取决于你的桌子大小和索引,在性能方面会有很大差异。

希望它有所帮助,