SQL Chọn mất quá nhiều thời gian để thực thi


9

Đó là một lựa chọn đơn giản từ một bảng tạm thời, bên trái tham gia một bảng hiện có trên khóa chính của nó, với hai lựa chọn phụ sử dụng top 1 tham chiếu bảng đã tham gia.

Trong mã:

SELECT
    TempTable.Col1,
    TempTable.Col2,
    TempTable.Col3,
    JoinedTable.Col1,
    JoinedTable.Col2,
    (
        SELECT TOP 1
            ThirdTable.Col1 -- Which is ThirdTable's Primary Key
        FROM
            ThirdTable
        WHERE
            ThirdTable.SomeColumn = JoinedTable.SomeColumn
    ) as ThirdTableColumn1,
    (
        SELECT TOP 1
            ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
        FROM
            ThirdTable
        WHERE
            ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
    ) as ThirdTableColumn2,
FROM
    #TempTable as TempTable
LEFT JOIN
    JoinedTable
ON (TempTable.PKColumn1 = JoinedTable.PKColumn1 AND 
    TempTable.PKColumn2 = JoinedTable.PKColumn2)
WHERE
    JoinedTable.WhereColumn IN  (1, 3)

Đây là một bản sao chính xác của truy vấn của tôi.

Nếu tôi loại bỏ hai lựa chọn phụ, nó sẽ chạy tốt và nhanh chóng. Với hai lựa chọn phụ, tôi nhận được khoảng 100 bản ghi mỗi giây, điều này cực kỳ chậm đối với truy vấn này vì nó sẽ trả về gần một triệu bản ghi.

Tôi đã kiểm tra xem mỗi bảng có Khóa chính không, tất cả đều làm. Tất cả chúng đều có Chỉ số VÀ số liệu thống kê cho các cột quan trọng của chúng, giống như các cột trong các mệnh đề WHERE và các cột trong mệnh đề THAM GIA. Bảng duy nhất không có khóa chính được xác định cũng như chỉ mục là bảng tạm thời, nhưng nó cũng không phải là vấn đề vì nó không phải là bảng liên quan đến các lựa chọn phụ chậm, và như tôi đã đề cập, không có lựa chọn phụ nào, nó chỉ chạy tốt.

Không có những cái TOP 1đó, nó trả về nhiều hơn một kết quả và gây ra lỗi.

Giúp ai

CHỈNH SỬA :

Vì vậy, kế hoạch thực hiện cho tôi biết tôi đang thiếu một Index. Tôi đã tạo ra nó và tạo lại một số chỉ mục khác. Sau một thời gian, kế hoạch thực hiện đã sử dụng chúng và truy vấn bây giờ chạy rất nhanh. Vấn đề duy nhất là tôi không thành công khi thực hiện lại điều này trên một máy chủ khác, cho cùng một truy vấn. Vì vậy, giải pháp của tôi sẽ là HINT mà SQL Server sẽ sử dụng chỉ mục nào.


Wow, thật ấn tượng. Nhưng thay vào đó, bạn có thể chia nó thành nhiều câu riêng biệt không? Ngoài ra, làm thế nào về Thủ tục lưu trữ thay thế?

2
@Adel Lựa chọn đó thực tế là một lựa chọn phụ bên trong Quy trình được lưu trữ. Toàn bộ điều này thực sự khá lớn, nhưng tôi chắc chắn 100% rằng đó là phần chính xác đang mất thời gian để thực hiện.

Sự thay đổi trong kế hoạch thực hiện, bao gồm các chỉ mục được chọn tự động rất có thể phải thực hiện với một thay đổi trong dữ liệu. Tôi sẽ đảm bảo các chỉ mục của bạn được bao phủ hoàn toàn hoặc động cơ sẽ có những đường dẫn bất ngờ như quét bảng. Tôi đề nghị xem xét kế hoạch thực hiện trên máy chủ mới (không có gợi ý) để xem bạn đang gặp phải sai lệch so với hệ thống ban đầu.
Robert Miller

Tôi hiểu rồi. Tôi chỉ thay đổi máy chủ, cơ sở dữ liệu là như nhau, với cùng một Chỉ mục. Tuy nhiên, dường như nó không tự động chọn sử dụng Chỉ mục của tôi. Nó thực hiện chính xác những gì bạn đã nói: Quét bảng.
Xì trum

Âm thanh như trình điều khiển truy vấn không thích bất kỳ chỉ mục nào của bảng cho truy vấn của bạn. Có kế hoạch thực hiện cho thấy một chỉ số còn thiếu?
Robert Miller

Câu trả lời:


7

Tôi nghĩ rằng trong một triệu truy vấn hồ sơ, bạn phải tránh những thứ như OUTER JOINS. Tôi đề nghị bạn sử dụng UNION ALLThay vì LEFT JOIN. Miễn là tôi nghĩ CROSS APPLYlà hiệu quả hơn truy vấn phụ trong mệnh đề chọn, tôi sẽ sửa đổi truy vấn được viết bởi Conard Frix, mà tôi nghĩ là chính xác.

Bây giờ: khi tôi bắt đầu sửa đổi truy vấn của mình, tôi nhận thấy rằng bạn có mệnh đề WHERE nói : JoinedTable.WhereColumn IN (1, 3). trong trường hợp này, nếu trường là null, điều kiện sẽ trở thành sai. vậy thì tại sao bạn lại sử dụng LEFT THAM GIA trong khi bạn đang lọc các hàng có giá trị null? chỉ cần thay thế LEFT JOINbằng INNER JOIN, tôi đảm bảo rằng nó sẽ trở nên nhanh hơn.

về INDEX:

xin lưu ý rằng khi bạn có một chỉ mục trên bàn, hãy nói

table1(a int, b nvarchar)

và chỉ mục của bạn là:

nonclustered index ix1 on table1(a)

và bạn muốn làm một cái gì đó như thế này:

select a,b from table1
where a < 10

trong chỉ mục của bạn, bạn chưa bao gồm cột, bvậy điều gì xảy ra?

nếu máy chủ sql sử dụng chỉ mục của bạn, nó sẽ phải tìm kiếm trong chỉ mục, được gọi là "Tìm kiếm chỉ mục" và sau đó tham khảo bảng chính để lấy cột b, được gọi là "Tra cứu" . Quy trình này có thể mất nhiều thời gian hơn so với việc quét chính bảng: "Quét bảng" .

nhưng dựa trên số liệu thống kê mà máy chủ sql có, trong những tình huống như vậy, nó hoàn toàn không thể sử dụng chỉ mục của bạn.

Vì vậy, trước hết hãy kiểm tra Execution Planxem liệu chỉ mục có được sử dụng không.

nếu có hoặc không có cả hai, hãy thay đổi chỉ mục của bạn để bao gồm tất cả các cột mà bạn đang chọn. nói như:

nonclustered index ix1 on table1(a) include(b)

trong trường hợp này, Tra cứu sẽ không cần thiết và truy vấn của bạn sẽ thực thi nhanh hơn rất nhiều.


1
Tôi không thể thay đổi liên kết trái sang tham gia Nội, nó sẽ làm hỏng kết quả, đó là một quy tắc kinh doanh: bảng thứ hai không nhất thiết phải có một hồ sơ liên quan. Ngoài ra, cột trong mệnh đề WHERE không chấp nhận giá trị null.
Smur

6

Đó là phụ chọn trong lựa chọn cột của bạn gây ra sự trở lại chậm. Bạn nên thử sử dụng các lựa chọn phụ của mình trong các liên kết bên trái hoặc sử dụng bảng dẫn xuất như tôi đã xác định bên dưới.

Sử dụng Joins trái cho hai trường hợp của Bảng thứ ba

SELECT
  TempTable.Col1,
  TempTable.Col2,
  TempTable.Col3,
  JoinedTable.Col1,
  JoinedTable.Col2,
  ThirdTable.Col1 AS ThirdTableColumn1,
  ThirdTable2.Col1 AS ThirdTableColumn2
FROM #TempTable as TempTable
LEFT JOIN JoinedTable ON (TempTable.PKColumn1 = JoinedTable.PKColumn2 AND 
    TempTable.PKColumn 2 = JoinedTable.PKColumn2)
LEFT JOIN ThirdTable ON ThirdTable.SomeColumn = JoinedTable.SomeColumn
LEFT JOIN ThirdTable ThirdTable2 ON ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
WHERE
    JoinedTable.WhereColumn IN  (1, 3)

Sử dụng bảng phái sinh

 SELECT 
      TempTable.Col1,
      TempTable.Col2,
      TempTable.Col3,
      DerivedTable.Col1,
      DerivedTable.Col2,
      DerivedTable.ThirdTableColumn1,
      DerivedTable.ThirdTableColumn2
 FROM #TempTable as TempTable
    LEFT JOIN (SELECT
                 JoinedTable.PKColumn2,
                 JoinedTable.Col1,
                 JoinedTable.Col2,
                 JoinedTable.WhereColumn,
                 ThirdTable.Col1 AS ThirdTableColumn1,
                 ThirdTable2.Col1 AS ThirdTableColumn2
               FROM JoinedTable
               LEFT JOIN ThirdTable ON ThirdTable.SomeColumn = JoinedTable.SomeColumn
               LEFT JOIN ThirdTable ThirdTable2 ON ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn) 
        DerivedTable ON (TempTable.PKColumn1 = DerivedTable .PKColumn2 AND 
        TempTable.PKColumn2 = DerivedTable.PKColumn2)
    WHERE
        DerivedTable.WhereColumn IN  (1, 3)

2

Thay vào đó hãy thử áp dụng chéo

SELECT
    TempTable.Col1,
    TempTable.Col2,
    TempTable.Col3,
    JoinedTable.Col1,
    JoinedTable.Col2,
    ThirdTableColumn1.col1,
    ThirdTableColumn2.col1

FROM
    #TempTable as TempTable
LEFT JOIN
    JoinedTable
ON (TempTable.PKColumn1 = JoinedTable.PKColumn2 AND 
    TempTable.PKColumn 2 = JoinedTablePKColumn2)

CROSS APPLY
(
        SELECT TOP 1
            ThirdTable.Col1 -- Which is ThirdTable's Primary Key
        FROM
            ThirdTable
        WHERE
            ThirdTable.SomeColumn = JoinedTable.SomeColumn
    ) as ThirdTableColumn1
CROSS APPLY    (
        SELECT TOP 1
            ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
        FROM
            ThirdTable
        WHERE
            ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
    ) as ThirdTableColumn2,
WHERE
    JoinedTable.WhereColumn IN  (1, 3)

Bạn cũng có thể sử dụng CTE và row_number hoặc truy vấn nội tuyến bằng MIN


2

Di chuyển các bit THAM GIA ra khỏi phần chính của mệnh đề và đặt nó làm phần phụ. Di chuyển nó đến phần WHERE và THAM GIA đảm bảo bạn không phải CHỌN TOP 1 nhiều lần, điều mà tôi tin là lý do cho sự chậm chạp của hte. Nếu bạn muốn kiểm tra điều này, hãy kiểm tra kế hoạch thực hiện.


2

Các ThirdTabletham chiếu, (phụ chọn trong ví dụ của bạn), cần cùng chú ý chỉ mục như bất kỳ phần nào khác của truy vấn.

Bất kể bạn sử dụng phụ chọn:

(
    SELECT TOP 1
        ThirdTable.Col1 -- Which is ThirdTable's Primary Key
    FROM
        ThirdTable
    WHERE
        ThirdTable.SomeColumn = JoinedTable.SomeColumn
) as ThirdTableColumn1,
(
    SELECT TOP 1
        ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
    FROM
        ThirdTable
    WHERE
        ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
) as ThirdTableColumn2,

THAM GIA TRÁI PHIẾU (theo đề xuất của John Hartsock):

LEFT JOIN ThirdTable ON ThirdTable.SomeColumn = JoinedTable.SomeColumn
LEFT JOIN ThirdTable ThirdTable2 ON ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn

ỨNG DỤNG CROSS (theo đề xuất của Conrad Frix):

CROSS APPLY
(
        SELECT TOP 1
            ThirdTable.Col1 -- Which is ThirdTable's Primary Key
        FROM
            ThirdTable
        WHERE
            ThirdTable.SomeColumn = JoinedTable.SomeColumn
    ) as ThirdTableColumn1
CROSS APPLY    (
        SELECT TOP 1
            ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
        FROM
            ThirdTable
        WHERE
            ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
    ) as ThirdTableColumn2

Bạn cần phải đảm bảo covering indexesđược định nghĩa cho ThirdTable.SomeColumnThirdTable.SomeOtherColumnvà các chỉ số là duy nhất. Điều này có nghĩa là bạn sẽ cần phải đủ điều kiện ThirdTabletham khảo để loại bỏ việc lựa chọn nhiều hàng và cải thiện hiệu suất. Sự lựa chọn của sub selects, LEFT JOINhoặc CROSS APPLYsẽ không thực sự quan trọng cho đến khi bạn nâng cao tính chọn lọc cho ThirdTable.SomeColumnThirdTable.SomeOtherColumnbằng cách bao gồm các cột hơn để đảm bảo tính chọn lọc độc đáo. Cho đến lúc đó, tôi mong hiệu suất của bạn sẽ tiếp tục bị ảnh hưởng.

Các covering indexchủ đề được độc đáo được giới thiệu bởi Maziar Taheri; Trong khi không lặp lại công việc của mình, tôi nhấn mạnh sự cần thiết phải sử dụng các chỉ số bao trùm.

Tóm lại: Cải thiện tính chọn lọc cho ThirdTable.SomeColumnThirdTable.SomeOtherColumntruy vấn (hoặc tham gia) bằng cách thêm các cột trong bảng có liên quan để đảm bảo khớp hàng duy nhất. Nếu điều này là không thể, thì bạn sẽ tiếp tục gặp vấn đề về hiệu suất khi động cơ đang bận rộn kéo theo các hàng sau đó bị vứt đi. Điều này tác động đến i / o, cpu của bạn và cuối cùng là kế hoạch thực hiện.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.