2017-03-22 89 views
6

Müşteri ayrıntılarını tutan bir veritabanı tablom var ve aradıklarında ayrıntılarını aramak için telefonlarını kullanıyoruz, ancak bu genellikle yaklaşık 2-3 saniye sürer. fazla veri olmaksızın 5 saniye sürüyor. Eğer tabloyu home_phone_no = '441903354676' kullanarak sorguladığımda bu, alt saniyede döner. Ancak eğer home_phone_no = '441903354676' veya business_phone_no = '441903354676' kullanarak sorgulanırsa, bu 5 saniye sürer.Kümelemeli olmayan bir dizin kullanırken SQL Query'm çok uzun sürüyor

Şimdi bazı 1,4 milyon müşteri kayıtları var. Ancak herkes belli bir şey görebiliyorsa veya bazı yararlı öneriler sunabiliyorsa, bu en çok hoş karşılanır.

Bu

Bu dizinin yapıdır

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] 

tablosunun yapısı şöyledir: Burada

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

saklı yordam edilir

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

her iki durumda da kullanılan sorgu ve yürütme planı lütfen dahil edin – TheGameiswar

cevap

6

endeksi olamaz home_phone_no = '441903354676' or business_phone_no = '441903354676' için kullanılır, ancak home_phone_no = '441903354676' and business_phone_no = '441903354676' için kullanılabilir.

Dizin anahtarının ilk sütunu için koşul olmadan dizin anahtarının ikinci sütununu kullanamaz.

ayrı destek dizinleri kullanmak istiyorsunuz, or kullanmak için, örneğin: Ayrıca

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

, bunu kümeleme anahtarıdır gibi endeksler üzerinde bulunan sütunu olarak [bill_account_no] dahil etmek gerekir ve sıra yok Böyle bir durumda, dolaylı olarak dahil edilmiştir.

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 

hala Uygun bir dizin oluşturma ve prosedürü güncellendikten sonra performans sorunları yaşıyorsanız, o zaman parametre soruna neden olan koklama eğer belirlemeye çalışmalıdır:

Sen aşağı tüm prosedürü kolaylaştırabilirsiniz .

aşağıdaki kapsayan this article by Paul White ile başlamak istiyorum:

  • İÇİN DURUMA (@:

    SQL Server sorgu ipuçları ve ayarlamak için diğer seçenekler parametresinin davranışı koklama bir dizi sağlar Parametre = değer) Sorgu ipucu, belirli bir değere bağlı olarak yeniden kullanılabilir bir plan oluşturur

  • OPTIMIZE FOR (@parameter UNKNOWN) belirli bir parametre için ortalama dağıtım istatistiklerini kullanır
  • Bilinmeyenler için
  • OPTİMİZE tüm parametreler için ortalama dağılımı
  • İLE RECOMPILE saklı bir teknik olarak
  • İSTEĞE BAĞLI (RECOMPILE) sorgu ipucu taze bir plan derler her yürütülmesi için yeni bir işlem planı derler (iz bayrağı 4136 ile aynı etkiyi) kullanan tek bir açıklamada dahi doğru endeksler ile
    ~ Parameter Sniffing, Embedding, and the RECOMPILE Options - Paul White
+0

Teşekkürler, bu yüzden geçerli dizin işe yaramaz ve sorgu çalışması daha iyi, diğer iki dizin oluşturulmalıdır? – Rusty

+0

Şimdi saklı bir prosedür kullandığınızı belirttiğiniz çok farklı bir teklif. SP'ler parametre koklamadan muzdarip olabilir. Hem saklı yordamları hem de dizinleri optimize etmek için birçok adım vardır, ancak sorgu planını yakalayarak başlamanız gerekir –

0

için (bu durumda, iki ayrı tek sütun indeksleri, home_phone_no üzerinde bir ve business_phone_no diğer), ne zaman VEYA yüklemler sen büyük olasılıkla tarama ile bitirin.

O, tüm sorguyu çoğaltma önlemek için belki de CTE ile, UNION ALL kullanmak çok daha iyidir:

Ayrıca
;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 

, ile yeniden önlemek, bu çok büyük bir çekiç. Bunun yerine OPTION (RECOMPILE) seçeneğini kullanın ve sadece gerçekten gerekliyse (burada durum böyle değil).

+0

Bu yardımcı oldu – Rusty