使用非聚集索引时,我的SQL查询花费的时间太长

Rus*_*sty 6 sql sql-server indexing

我有一个数据库表,其中包含客户详细信息,当他们打电话时,我们使用他们的电话查找他们的详细信息,但这通常需要大约2-3秒,但最近它花了5秒没有额外的数据.如果我使用home_phone_no ='441903354676'查询表,则返回sub seconds.但如果使用home_phone_no ='441903354676'或business_phone_no ='441903354676'进行查询,则需要5秒钟.

现在有大约140万的客户记录.但是,如果任何人都可以看到任何明显的或提供一些有用的建议,这是最受欢

这是表的结构

CREATE TABLE [dbo].[CCDB_ICR]
(
                [bill_account_no] [varchar](10) NOT NULL,
                [reference_id] [varchar](11) NULL,
                [bill_account_status] [varchar](2) NULL,
                [customer_type] [varchar](1) NULL,
                [customer_name] [varchar](56) NULL,
                [property_address] [varchar](69) NULL,
                [outer_post_code] [varchar](4) NULL,
                [inner_post_code] [varchar](3) NULL,
                [customer_move_in_date] [datetime2](7) NULL,
                [customer_move_out_date] [datetime2](7) NULL,
                [debt_flag] [varchar](1) NULL,
                [payment_category_flag] [varchar](2) NULL,
                [payment_plan_flag] [varchar](1) NULL,
                [key_customer_flag] [varchar](1) NULL,
                [home_phone_no] [varchar](12) NULL,
                [business_phone_no] [varchar](12) NULL,
                [contact_type] [varchar](4) NULL,
                [contact_code] [varchar](1) NULL,
                [contact_method] [varchar](1) NULL,
                [contact_date] [date] NULL,
                [contact_time] [varchar](5) NULL,
                [contact_status] [varchar](1) NULL,
                [contact_unit_resp] [varchar](4) NULL,
                [outstanding_balance] [decimal](9, 2) NULL,
                [date_time_inserted] [datetime] NOT NULL,
                [date_time_updated] [datetime] NULL,

    CONSTRAINT [PK_CCDB_ICR] 
        PRIMARY KEY CLUSTERED([bill_account_no] ASC)
                    WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
                          IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, 
                          ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)

这是索引的结构:

CREATE NONCLUSTERED INDEX [NC_Business&Home_Phone$CCDB_ICR] 
    ON [dbo].[CCDB_ICR] ([home_phone_no] ASC, [business_phone_no] ASC)
    INCLUDE ([bill_account_no]) 
Run Code Online (Sandbox Code Playgroud)

这是存储过程

ALTER procedure [dbo].[GET_ACCOUNT_BY_PHONE_NUMBER]
(
@CLI varchar(12),
@RETURN_VALUE int out,
@NUMBER_OF_ACCOUNTS int out,
@ACCOUNT_NUMBER varchar(10) out
)
as
Begin Try
      declare @ret int
      Select @ret=COUNT(*) from CCDB_ICR where home_phone_no=@CLI or business_phone_no=@CLI
      if @ret=0
      select @RETURN_VALUE=0,
      @NUMBER_OF_ACCOUNTS=0,
      @ACCOUNT_NUMBER=null
      else if @ret=1
      select @RETURN_VALUE=0,
      @NUMBER_OF_ACCOUNTS=1,
      @ACCOUNT_NUMBER=(Select  bill_account_no from CCDB_ICR where home_phone_no=@CLI or business_phone_no=@CLI)
      else if @ret>1
      select @RETURN_VALUE=0,
      @NUMBER_OF_ACCOUNTS=@ret ,
      @ACCOUNT_NUMBER=null
end Try

Begin Catch
      select @RETURN_VALUE=-1,
      @NUMBER_OF_ACCOUNTS=null ,
      @ACCOUNT_NUMBER=null
End Catch
Run Code Online (Sandbox Code Playgroud)

Sql*_*Zim 6

索引不能用于home_phone_no = '441903354676' or business_phone_no = '441903354676',但它可以用于home_phone_no = '441903354676' and business_phone_no = '441903354676'.

如果索引键的第一列没有条件,它将无法使用索引键的第二列.

要使用or,您可以使用单独的支持索引,例如:

create nonclustered index [NC_Business&Home_Phone$CCDB_ICR] 
  on [dbo].[CCDB_ICR] ([home_phone_no] asc);

create nonclustered index [NC_Business&Business_Phone$CCDB_ICR] 
  on [dbo].[CCDB_ICR] ([business_phone_no] asc); 
Run Code Online (Sandbox Code Playgroud)

此外,您不需要[bill_account_no]在索引中包含作为包含列,因为它是群集键,因此已经隐式包含.

您可以将整个过程简化为:

alter procedure [dbo].[get_account_by_phone_number] (
    @cli varchar(12)
  , @return_value int out
  , @number_of_accounts int out
  , @account_number varchar(10) out
) as
begin;
  set nocount, xact_abort on;

  set @return_value = 0;
  set @number_of_accounts = 0;

  select 
      @number_of_accounts = count(*)
    , @account_number = case when count(*)=1 then max(bill_account_no) else null end
  from ccdb_icr 
  where home_phone_no=@cli 
     or business_phone_no=@cli;
end;
go
Run Code Online (Sandbox Code Playgroud)

如果在创建适当的索引并更新过程后仍遇到性能问题,则应尝试确定参数嗅探是否导致问题.

我将从保罗怀特的这篇文章开始,其中包括以下内容:

SQL Server提供了一系列查询提示和其他选项来调整参数嗅探的行为:

  • OPTIMIZE FOR(@parameter = value)查询提示基于特定值构建可重用计划
  • OPTIMIZE FOR(@parameter UNKNOWN)使用特定参数的平均分布统计信息
  • OPTIMIZE FOR UNKNOWN使用所有参数的平均分布(与跟踪标志4136相同的效果)
  • WITH RECOMPILE存储过程选项为每次执行编译新的过程计划
  • OPTION(RECOMPILE)查询提示为单个语句编译新计划
    参数嗅探,嵌入和RECOMPILE选项--Paul White