Cập nhật bảng hiệu quả bằng THAM GIA


8

Tôi có một bảng có các chi tiết của các hộ gia đình và một bảng khác có các chi tiết của tất cả những người liên quan đến các hộ gia đình. Đối với bảng hộ gia đình tôi có một khóa chính được xác định bằng hai cột trong đó - [tempId,n]. Đối với bảng người tôi có một khóa chính được xác định bằng 3 cột của nó[tempId,n,sporder]

Sử dụng cách sắp xếp được quyết định bởi việc lập chỉ mục được nhóm trên các khóa chính, tôi đã tạo một ID duy nhất cho từng hộ gia đình [HHID]và từng [PERID]bản ghi (đoạn trích dưới đây là để tạo PERID]:

 ALTER TABLE dbo.persons
 ADD PERID INT IDENTITY
 CONSTRAINT [UQ dbo.persons HHID] UNIQUE;

Bây giờ, bước tiếp theo của tôi là liên kết mỗi người với các hộ gia đình tương ứng; ánh xạ a [PERID]đến a [HHID]. Lối băng qua lại giữa hai bảng dựa trên hai cột [tempId,n]. Đối với điều này, tôi có tuyên bố tham gia bên trong sau đây.

UPDATE t1
  SET t1.HHID = t2.HHID
  FROM dbo.persons AS t1
  INNER JOIN dbo.households AS t2
  ON t1.tempId = t2.tempId AND t1.n = t2.n;

Tôi có tổng cộng 1928783 hồ sơ hộ gia đình và 5239842 hồ sơ cá nhân. Thời gian thực hiện hiện tại rất cao.

Bây giờ, câu hỏi của tôi:

  1. Có thể tối ưu hóa truy vấn này hơn nữa? Tổng quát hơn, các quy tắc ngón tay cái để tối ưu hóa truy vấn tham gia là gì?
  2. Có một cấu trúc truy vấn khác có thể đạt được kết quả tôi muốn với thời gian thực hiện tốt hơn không?

Tôi đã tải lên kế hoạch thực hiện được tạo bởi SQL Server 2008 cho toàn bộ tập lệnh lên SQLPerformance.com

Câu trả lời:


19

Tôi khá chắc chắn các định nghĩa bảng gần với điều này:

CREATE TABLE dbo.households
(
    tempId  integer NOT NULL,
    n       integer NOT NULL,
    HHID    integer IDENTITY NOT NULL,

    CONSTRAINT [UQ dbo.households HHID] 
        UNIQUE NONCLUSTERED (HHID),

    CONSTRAINT [PK dbo.households tempId, n]
    PRIMARY KEY CLUSTERED (tempId, n)
);

CREATE TABLE dbo.persons
(
    tempId  integer NOT NULL,
    sporder integer NOT NULL,
    n       integer NOT NULL,
    PERID   integer IDENTITY NOT NULL,
    HHID    integer NOT NULL,

    CONSTRAINT [UQ dbo.persons HHID]
        UNIQUE NONCLUSTERED (PERID),

    CONSTRAINT [PK dbo.persons tempId, n, sporder]
        PRIMARY KEY CLUSTERED (tempId, n, sporder)
);

Tôi không có số liệu thống kê cho các bảng này hoặc dữ liệu của bạn, nhưng ít nhất những điều sau đây sẽ đặt chính xác số lượng bảng (số trang là một phỏng đoán):

UPDATE STATISTICS dbo.persons 
WITH 
    ROWCOUNT = 5239842, 
    PAGECOUNT = 100000;

UPDATE STATISTICS dbo.households 
WITH 
    ROWCOUNT = 1928783, 
    PAGECOUNT = 25000;

Phân tích kế hoạch truy vấn

Truy vấn bạn có bây giờ là:

UPDATE P
SET HHID = H.HHID
FROM dbo.households AS H
JOIN dbo.persons AS P
    ON P.tempId = H.tempId
    AND P.n = H.n;

Điều này tạo ra kế hoạch khá kém hiệu quả:

Gói mặc định

Các vấn đề chính trong kế hoạch này là tham gia băm và sắp xếp. Cả hai đều yêu cầu cấp bộ nhớ (phép nối băm cần xây dựng bảng băm và sắp xếp cần có chỗ để lưu trữ các hàng trong khi sắp xếp tiến trình). Plan Explorer cho thấy truy vấn này đã được cấp 765 MB:

Cấp bộ nhớ

Đây là khá nhiều bộ nhớ máy chủ để dành cho một truy vấn! Hơn nữa, việc cấp bộ nhớ này được cố định trước khi bắt đầu thực hiện dựa trên ước tính kích thước và số lượng hàng.

Nếu bộ nhớ hóa ra không đủ trong thời gian thực hiện, ít nhất một số dữ liệu cho hàm băm và / hoặc sắp xếp sẽ được ghi vào đĩa tempdb vật lý . Điều này được gọi là 'tràn' và nó có thể là một hoạt động rất chậm. Bạn có thể theo dõi các sự cố tràn này (trong SQL Server 2008) bằng cách sử dụng các sự kiện Profiler Hash Cảnh báoSắp xếp cảnh báo .

Ước tính cho đầu vào xây dựng của bảng băm là rất tốt:

Đầu vào băm

Ước tính cho đầu vào sắp xếp ít chính xác hơn:

Sắp xếp đầu vào

Bạn sẽ phải sử dụng Profiler để kiểm tra, nhưng tôi nghi ngờ loại này sẽ tràn sang tempdb trong trường hợp này. Cũng có thể bảng băm tràn ra, nhưng điều đó ít rõ ràng hơn.

Lưu ý rằng bộ nhớ dành riêng cho truy vấn này được phân chia giữa bảng băm và sắp xếp, vì chúng chạy đồng thời. Thuộc tính gói Phân số bộ nhớ hiển thị số lượng tương đối của cấp bộ nhớ dự kiến ​​sẽ được sử dụng cho mỗi thao tác.

Tại sao Sắp xếp và Hash?

Sắp xếp được giới thiệu bởi trình tối ưu hóa truy vấn để đảm bảo rằng các hàng đến toán tử Cập nhật chỉ mục cụm theo thứ tự khóa cụm. Điều này thúc đẩy truy cập tuần tự vào bảng, thường hiệu quả hơn nhiều so với truy cập ngẫu nhiên.

Phép nối băm là một lựa chọn ít rõ ràng hơn, bởi vì đầu vào của nó có kích thước tương tự (dù sao cũng là xấp xỉ đầu tiên). Tham gia băm là tốt nhất trong đó một đầu vào (đầu vào xây dựng bảng băm) tương đối nhỏ.

Trong trường hợp này, mô hình chi phí của trình tối ưu hóa xác định rằng phép nối băm rẻ hơn trong ba tùy chọn (hàm băm, hợp nhất, vòng lặp lồng nhau).

Cải thiện hiệu suất

Mô hình chi phí không phải lúc nào cũng đúng. Nó có xu hướng ước tính quá mức chi phí tham gia hợp nhất song song, đặc biệt là khi số lượng chủ đề tăng lên. Chúng tôi có thể buộc tham gia hợp nhất với một gợi ý truy vấn:

UPDATE P
SET HHID = H.HHID
FROM dbo.households AS H
JOIN dbo.persons AS P
    ON P.tempId = H.tempId
    AND P.n = H.n
OPTION (MERGE JOIN);

Điều này tạo ra một gói không yêu cầu nhiều bộ nhớ (vì hợp nhất không cần bảng băm):

Kế hoạch hợp nhất

Sắp xếp có vấn đề vẫn còn đó, bởi vì hợp nhất chỉ giữ nguyên thứ tự của các khóa tham gia của nó (tempId, n) nhưng các khóa được nhóm là (tempId, n, sporder). Bạn có thể thấy kế hoạch hợp nhất thực hiện không tốt hơn kế hoạch tham gia băm.

Vòng lặp lồng nhau Tham gia

Chúng ta cũng có thể thử tham gia một vòng lặp lồng nhau:

UPDATE P
SET HHID = H.HHID
FROM dbo.households AS H
JOIN dbo.persons AS P
    ON P.tempId = H.tempId
    AND P.n = H.n
OPTION (LOOP JOIN);

Kế hoạch cho truy vấn này là:

Kế hoạch vòng lặp lồng nhau

Kế hoạch truy vấn này được coi là tồi tệ nhất bởi mô hình chi phí của trình tối ưu hóa, nhưng nó có một số tính năng rất đáng mong đợi. Đầu tiên, các vòng lặp lồng nhau không yêu cầu cấp bộ nhớ. Thứ hai, nó có thể duy trì thứ tự khóa từ Personsbảng để không cần sắp xếp rõ ràng. Bạn có thể thấy kế hoạch này thực hiện tương đối tốt, thậm chí có thể đủ tốt.

Vòng lặp song song lồng nhau

Hạn chế lớn với kế hoạch các vòng lặp lồng nhau là nó chạy trên một luồng duy nhất. Có khả năng truy vấn này được hưởng lợi từ tính song song, nhưng trình tối ưu hóa quyết định không có lợi thế nào khi thực hiện điều đó ở đây. Điều này cũng không hẳn đúng. Thật không may, không có gợi ý truy vấn tích hợp để có kế hoạch song song, nhưng có một cách không có giấy tờ:

UPDATE t1
  SET t1.HHID = t2.HHID
  FROM dbo.persons AS t1
  INNER JOIN dbo.households AS t2
  ON t1.tempId = t2.tempId AND t1.n = t2.n
OPTION (LOOP JOIN, QUERYTRACEON 8649);

Kích hoạt cờ theo dõi 8649 với QUERYTRACEONgợi ý tạo ra kế hoạch này:

Kế hoạch song song lồng nhau

Bây giờ chúng tôi có một kế hoạch tránh sắp xếp, không yêu cầu thêm bộ nhớ để tham gia và sử dụng song song một cách hiệu quả. Bạn sẽ tìm thấy truy vấn này thực hiện tốt hơn nhiều so với các lựa chọn thay thế.

Thông tin thêm về tính song song trong bài viết của tôi Buộc Kế hoạch thực hiện truy vấn song song :


1

Nhìn vào kế hoạch truy vấn của bạn, có thể vấn đề thực sự của bạn có thể không phải là sự tham gia mà là quá trình cập nhật thực tế.

Từ những gì tôi có thể thấy, có khả năng bạn đang cập nhật tất cả các bản ghi cá nhân trong cơ sở dữ liệu của mình và cập nhật các chỉ mục (Tôi không thể thấy các chỉ mục này có gì để tôi không biết liệu đó có phải là một yếu tố không)

Nếu đây là nhiệm vụ một lần, bạn có thể vô hiệu hóa các chỉ mục, chạy cập nhật và xây dựng lại các chỉ mục không?

Khi bạn đã nhập dữ liệu, bạn có thể thêm mệnh đề where vào truy vấn của mình để chỉ cập nhật những bản ghi cần cập nhật

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.