2017-03-22 43 views
6

Tôi có bảng cơ sở dữ liệu chứa chi tiết khách hàng và khi họ gọi điện, chúng tôi sử dụng điện thoại của họ để tra cứu chi tiết, nhưng thường mất khoảng 2-3 giây đã mất 5 giây mà không có thêm dữ liệu. Nếu tôi truy vấn bảng bằng cách sử dụng home_phone_no = '441903354676' điều này trả về trong phụ thứ hai. Nhưng nếu nó được truy vấn bằng cách sử dụng home_phone_no = '441903354676' hoặc business_phone_no = '441903354676' thì điều này mất 5 giây.Truy vấn SQL của tôi mất quá nhiều thời gian khi sử dụng chỉ mục không được nhóm

Hiện có một số bản ghi khách hàng 1.4m. Nhưng nếu bất cứ ai có thể nhìn thấy bất cứ điều gì rõ ràng hoặc cung cấp một số gợi ý hữu ích này được chào đón nhất.

Đây là cấu trúc của bảng

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] 

Đây là cấu trúc của chỉ số:

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

Dưới đây là thủ tục lưu trữ

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

hãy bao gồm truy vấn được sử dụng và cũng là kế hoạch thực hiện trong cả hai trường hợp – TheGameiswar

Trả lời

6

Chỉ số không thể được sử dụng cho home_phone_no = '441903354676' or business_phone_no = '441903354676', nhưng nó có thể được sử dụng cho home_phone_no = '441903354676' and business_phone_no = '441903354676'.

Nó sẽ không thể sử dụng cột thứ hai của khóa chỉ mục mà không có điều kiện cho cột đầu tiên của khóa chỉ mục.

Để sử dụng or, bạn sẽ sử dụng các chỉ số hỗ trợ riêng biệt, ví dụ:

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

Ngoài ra, bạn không cần phải bao gồm [bill_account_no] như một cột bao gồm trên các chỉ số của bạn vì nó là chìa khóa clustering, và như như vậy đã được bao gồm ngầm.

Bạn có thể đơn giản hóa toàn bộ quy trình của bạn xuống đến:

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 

Nếu bạn vẫn gặp vấn đề hiệu suất sau khi tạo các chỉ số thích hợp và cập nhật các thủ tục, sau đó bạn nên cố gắng xác định nếu tham số sniffing gây ra vấn đề .

tôi sẽ bắt đầu với this article by Paul White trong đó bao gồm những điều sau đây:

SQL Server cung cấp một loạt các gợi ý truy vấn và các tùy chọn khác để điều chỉnh hành vi của tham số sniffing:

  • Các tối ưu hóa cho (@ gợi ý truy vấn parameter = value) xây dựng kế hoạch tái sử dụng dựa trên giá trị cụ thể
  • OPTIMIZE FOR (@parameter UNKNOWN) sử dụng thống kê phân phối trung bình cho một thông số cụ thể
  • tối ưu hóa cho UNKNOWN sử dụng phân phối trung bình cho tất cả các thông số (cùng tác dụng như dấu vết cờ 4136)
  • Các VỚI biên dịch lại lựa chọn thủ tục lưu trữ biên dịch một kế hoạch quy trình mới cho mỗi thực
  • Các OPTION (biên dịch lại) truy vấn gợi ý biên dịch một kế hoạch tươi cho một tuyên bố cá nhân
    ~ Parameter Sniffing, Embedding, and the RECOMPILE Options - Paul White
+0

Cảm ơn, vì vậy chỉ mục hiện tại là vô ích và cho truy vấn hoạt động tốt hơn, hai chỉ mục khác cần phải được xây dựng? – Rusty

+0

Đó là một đề xuất rất khác ngay bây giờ mà bạn đã chỉ ra rằng bạn đang sử dụng một thủ tục được lưu trữ. SP có thể bị ngửi thông số. Có nhiều bước để tối ưu hóa cả các thủ tục và chỉ mục được lưu trữ, nhưng bạn cần bắt đầu bằng cách bắt kế hoạch truy vấn –

0

Ngay cả với chỉ số chính xác (trong trường hợp này, hai chỉ số đơn col riêng biệt, một trên home_phone_no và khác trên business_phone_no), khi bạn HOẶC vị từ bạn sẽ có khả năng nhất kết thúc bằng việc quét.

Nó là tốt hơn để sử dụng UNION ALL, có lẽ với một CTE để tránh sao chép toàn bộ truy vấn:

;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 

Ngoài ra, tránh các VỚI biên dịch lại, nó quá lớn một cái búa. Sử dụng OPTION (RECOMPILE) thay vào đó, và chỉ khi thực sự cần thiết (mà tôi giả định không phải là trường hợp ở đây).

+0

Cảm ơn điều này hữu ích – Rusty

Các vấn đề liên quan