2017-03-22 6 views
6

私は顧客の詳細を保持するデータベーステーブルを持っており、電話をかけて電話を使って詳細を検索しますが、それは余分なデータなしで5秒を取っている。私がhome_phone_no = '441903354676'を使ってテーブルを照会すると、これは副次的に戻ります。しかし、home_phone_no = '441903354676'またはbusiness_phone_no = '441903354676'を使用して照会すると、これには5秒かかります。クラスタ化されていないインデックスを使用すると、SQLクエリが時間がかかりすぎる

1.4mの顧客記録があります。しかし、誰かが何かを目に見えるものと見なすことができれば、これは大歓迎です。

これは、テーブルの構造

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] 

これは、インデックスの構造である:ここ

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]) 

インデックスをすることはできませんストアドプロシージャ

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 [email protected] or [email protected] 
     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 [email protected] or [email protected]) 
     else if @ret>1 
     select @RETURN_VALUE=0, 
     @[email protected] , 
     @ACCOUNT_NUMBER=null 
end Try 

Begin Catch 
     select @RETURN_VALUE=-1, 
     @NUMBER_OF_ACCOUNTS=null , 
     @ACCOUNT_NUMBER=null 
End Catch 
+0

両方の場合に使用されるクエリと実行計画も含めてください – TheGameiswar

答えて

6

ありますhome_phone_no = '441903354676' or business_phone_no = '441903354676'に使用されていますが、home_phone_no = '441903354676' and business_phone_no = '441903354676'に使用できます。

インデックスキーの2番目の列は、インデックスキーの最初の列の条件なしでは使用できません。

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); 

また、あなたはそれがクラスタ化キーであるとして、あなたのインデックスに含まれる列として[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 [email protected] 
    or [email protected]; 
end; 
go 

私は、次のカバーするthis article by Paul Whiteで始まります:

SQL Serverがスニッフィングパラメータの動作をチューニングするクエリヒントやその他のオプションの範囲を提供する:

  • OPTIMIZE FOR(@パラメータ=値)クエリヒント特定の値に基づいて再利用可能なプランを作成します
  • OPTIMIZE FOR(@パラメータUNKNOWN)は、特定のパラメータの平均分布統計を使用します。
  • UNKNOWN FOR
  • OPTIMIZEは、すべてのパラメータの平均分布
  • WITH RECOMPILEストアドプロシージャオプションが
  • OPTION(RECOMPILE)クエリヒントは、新鮮な計画をコンパイルすべての実行のために新鮮な手順の計画をコンパイル(トレースフラグ4136と同じ効果)を使用しでも(この場合、2つの別個の単一-COLインデックス、business_phone_no上home_phone_no、他方では1)の正しいインデックスで、ときあなたやあなたが最も可能性が高いでしょう述語個々の文
    Parameter Sniffing, Embedding, and the RECOMPILE Options - Paul White
+0

ありがとう、現在のインデックスは役に立たず、クエリがうまく機能するためには、他の2つのインデックスを作成する必要がありますか? – Rusty

+0

これは、ストアドプロシージャを使用していることを示したので、これは非常に異なる命題です。 SPはパラメータスニッフィングに苦しむ可能性があります。ストアドプロシージャとインデックスの両方を最適化するには多くの手順がありますが、クエリプランをキャプチャして開始する必要があります –

0

用スキャンで終わる。

全体のクエリの重複を避けるためにおそらくCTEで、UNION ALLを使用することがはるかに優れています:

また
;with x as (
    -- your query here 
) 
select * from x where home_phone_no = @home_phone_no 
union all 
select * from x where business_phone_no = @business_phone_no 

、WITH RECOMPILEを避けるため、それはあまりにも大きなハンマーです。代わりにOPTION(RECOMPILE)を使用してください。本当に必要な場合にのみ使用してください(私はここではそうではないと想定しています)。

+0

ありがとう – Rusty

関連する問題