Tôi đang cố gắng dỗ một số hiệu suất cao hơn từ một truy vấn đang truy cập vào một bảng có ~ 250 triệu bản ghi. Từ việc tôi đọc kế hoạch thực hiện (không ước tính) thực tế, nút cổ chai đầu tiên là một truy vấn trông như thế này:
select
b.stuff,
a.added,
a.value
from
dbo.hugetable a
inner join
#smalltable b on a.fk = b.pk
where
a.added between @start and @end;
Xem thêm về các định nghĩa của các bảng và chỉ mục liên quan.
Kế hoạch thực hiện chỉ ra rằng một vòng lặp lồng nhau đang được sử dụng trên #smalltable và việc quét chỉ mục trên hugetable đang được thực hiện 480 lần (cho mỗi hàng trong #smalltable). Điều này dường như ngược với tôi, vì vậy tôi đã cố gắng buộc một phép nối hợp nhất được sử dụng thay thế:
select
b.stuff,
a.added,
a.value
from
dbo.hugetable a with(index = ix_hugetable)
inner merge join
#smalltable b with(index(1)) on a.fk = b.pk
where
a.added between @start and @end;
Chỉ mục trong câu hỏi (xem bên dưới để định nghĩa đầy đủ) bao gồm các cột fk (vị từ nối), được thêm vào (được sử dụng trong mệnh đề where) & id (vô dụng) theo thứ tự tăng dần và bao gồm giá trị .
Tuy nhiên, khi tôi thực hiện việc này, truy vấn sẽ chuyển từ 2 1/2 phút sang hơn 9. Tôi đã hy vọng rằng các gợi ý sẽ buộc một phép nối hiệu quả hơn chỉ thực hiện một lần vượt qua mỗi bảng, nhưng rõ ràng là không.
Bất kỳ hướng dẫn đều được chào đón. Thông tin bổ sung được cung cấp nếu được yêu cầu.
Cập nhật (2011/06/02)
Sau khi sắp xếp lại việc lập chỉ mục trên bàn, tôi đã thực hiện các bước hiệu suất đáng kể, tuy nhiên tôi đã gặp một trở ngại mới khi nói đến việc tóm tắt dữ liệu trong bảng lớn. Kết quả là một cuộc so sánh theo tháng, hiện tại trông như sau:
select
b.stuff,
datediff(month, 0, a.added),
count(a.value),
sum(case when a.value > 0 else 1 end) -- this triples the running time!
from
dbo.hugetable a
inner join
#smalltable b on a.fk = b.pk
group by
b.stuff,
datediff(month, 0, a.added);
Hiện tại, hugetable có một chỉ mục được nhóm pk_hugetable (added, fk)
(khóa chính) và một chỉ mục không được phân cụm theo cách khác ix_hugetable (fk, added)
.
Không có cột thứ 4 ở trên, trình tối ưu hóa sử dụng phép nối vòng lặp lồng nhau như trước, sử dụng #smalltable làm đầu vào bên ngoài và chỉ mục không phân cụm tìm kiếm như vòng lặp bên trong (thực hiện lại 480 lần). Điều tôi quan tâm là sự chênh lệch giữa các hàng ước tính (12.958,4) và các hàng thực tế (74,668,468). Chi phí tương đối của những lần tìm kiếm này là 45%. Thời gian chạy tuy nhiên dưới một phút.
Với cột thứ 4, thời gian chạy tăng đột biến lên 4 phút. Nó tìm kiếm trên chỉ mục được nhóm lần này (2 lần thực hiện) với cùng một chi phí tương đối (45%), tổng hợp thông qua khớp băm (30%), sau đó thực hiện băm tham gia trên #smalltable (0%).
Tôi không chắc chắn về hành động tiếp theo của mình. Mối quan tâm của tôi là không tìm kiếm phạm vi ngày cũng như vị từ tham gia được đảm bảo hoặc thậm chí tất cả những gì có khả năng làm giảm đáng kể tập kết quả. Phạm vi ngày trong hầu hết các trường hợp sẽ chỉ cắt có thể 10 - 15% hồ sơ và tham gia bên trong trên fk có thể lọc ra có thể 20-30%.
Theo yêu cầu của Will A, kết quả của sp_spaceused
:
name | rows | reserved | data | index_size | unused
hugetable | 261774373 | 93552920 KB | 18373816 KB | 75167432 KB | 11672 KB
#smalltable được định nghĩa là:
create table #endpoints (
pk uniqueidentifier primary key clustered,
stuff varchar(6) null
);
Trong khi dbo.hugetable được định nghĩa là:
create table dbo.hugetable (
id uniqueidentifier not null,
fk uniqueidentifier not null,
added datetime not null,
value decimal(13, 3) not null,
constraint pk_hugetable primary key clustered (
fk asc,
added asc,
id asc
)
with (
pad_index = off, statistics_norecompute = off,
ignore_dup_key = off, allow_row_locks = on,
allow_page_locks = on
)
on [primary]
)
on [primary];
Với chỉ số sau được xác định:
create nonclustered index ix_hugetable on dbo.hugetable (
fk asc, added asc, id asc
) include(value) with (
pad_index = off, statistics_norecompute = off,
sort_in_tempdb = off, ignore_dup_key = off,
drop_existing = off, online = off,
allow_row_locks = on, allow_page_locks = on
)
on [primary];
Trường id là dự phòng, một vật phẩm từ một DBA trước đó đã nhấn mạnh rằng tất cả các bảng ở mọi nơi nên có GUID, không có ngoại lệ.