Hiệu suất của các chỉ mục không được nhóm trên Heaps so với các chỉ mục được nhóm


39

Sách trắng 2007 này so sánh hiệu suất của các câu lệnh chọn / chèn / xóa / cập nhật và phạm vi chọn riêng lẻ trên một bảng được tổ chức dưới dạng một chỉ mục được nhóm so với trên một bảng được tổ chức thành một đống với chỉ mục không được nhóm trên cùng một cột chính như CI bàn.

Nói chung, tùy chọn chỉ mục được nhóm thực hiện tốt hơn trong các thử nghiệm vì chỉ có một cấu trúc để duy trì và vì không cần phải tra cứu dấu trang.

Một trường hợp thú vị tiềm năng không được đề cập trong bài báo sẽ là so sánh giữa một chỉ mục không được nhóm trên một heap so với một chỉ mục không được nhóm trên một chỉ mục được nhóm. Trong trường hợp đó, tôi đã mong đợi heap thậm chí có thể hoạt động tốt hơn khi một lần ở SQL Server cấp độ lá NCI có RID để theo dõi trực tiếp thay vì phải đi qua chỉ mục được nhóm.

Có ai biết về thử nghiệm chính thức tương tự đã được thực hiện trong lĩnh vực này và nếu vậy kết quả là gì?

Câu trả lời:


41

Để kiểm tra yêu cầu của bạn, tôi đã tạo 2 bảng theo sơ đồ này:

  • 7,9 triệu hồ sơ đại diện cho thông tin số dư.
  • một lĩnh vực nhận dạng từ 1 đến 7,9 triệu
  • một trường số nhóm các hồ sơ trong khoảng 500k nhóm.

Bảng đầu tiên được gọi heapcó một chỉ mục không được nhóm trên trường group. Bảng thứ hai được gọi clustcó một chỉ mục được nhóm trên trường tuần tự được gọi keyvà một chỉ mục không được bao gồm trên trườnggroup

Các thử nghiệm đã được chạy trên bộ xử lý I5 M540 với 2 lõi siêu phân luồng, bộ nhớ 4Gb và windows 7 64 bit.

Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (X64) 
Apr  2 2010 15:48:46 
Developer Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)  

Cập nhật vào ngày 9 tháng 3 năm 2011 : Tôi đã thực hiện một điểm chuẩn mở rộng thứ hai bằng cách chạy mã .net sau đây và ghi lại Thời lượng, CPU, Đọc, Viết và RowCounts trong Sql Server Profiler. (CommandText được sử dụng sẽ được đề cập trong kết quả.)

LƯU Ý: CPU và Thời lượng được biểu thị bằng mili giây

  • 1000 truy vấn
  • không có truy vấn CPU nào bị loại khỏi kết quả
  • 0 hàng bị ảnh hưởng được loại bỏ khỏi kết quả
int[] idList = new int[] { 6816588, 7086702, 6498815 ... }; // 1000 values here.
using (var conn = new SqlConnection(@"Data Source=myserver;Initial Catalog=mydb;Integrated Security=SSPI;"))
            {
                conn.Open();
                using (var cmd = new SqlCommand())
                {
                    cmd.Connection = conn;
                    cmd.CommandType = CommandType.Text;
                    cmd.CommandText = "select * from heap where common_key between @id and @id+1000"; 
                    cmd.Parameters.Add("@id", SqlDbType.Int);
                    cmd.Prepare();
                    foreach (int id in idList)
                    {
                        cmd.Parameters[0].Value = id;

                        using (var reader = cmd.ExecuteReader())
                        {
                            int count = 0;
                            while (reader.Read())
                            {
                                count++;
                            }
                            Console.WriteLine(String.Format("key: {0} => {1} rows", id, count));
                        }
                    }
                }
            }

Kết thúc cập nhật vào ngày 9 tháng 3 năm 2011 .

Hiệu suất CHỌN

Để kiểm tra số hiệu suất, tôi đã thực hiện các truy vấn sau một lần trên bảng heap và một lần trên bảng clust:

select * from heap/clust where group between 5678910 and 5679410
select * from heap/clust where group between 6234567 and 6234967
select * from heap/clust where group between 6455429 and 6455729
select * from heap/clust where group between 6655429 and 6655729
select * from heap/clust where group between 6955429 and 6955729
select * from heap/clust where group between 7195542 and 7155729

Kết quả của điểm chuẩn này là dành cho heap:

rows  reads CPU   Elapsed 
----- ----- ----- --------
1503  1510  31ms  309ms
401   405   15ms  283ms
2700  2709  0ms   472ms
0     3     0ms   30ms
2953  2962  32ms  257ms
0     0     0ms   0ms

Cập nhật ngày 9 tháng 3 năm 2011 : cmd.CommandText = "select * from heap where group between @id and @id+1000";

  • 721 Hàng có> 0 CPU và ảnh hưởng đến hơn 0 hàng
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1001      69788    6368         -         
Cpu            15        374      37   0.00754
Reads        1069      91459    7682   1.20155
Writes          0          0       0   0.00000
Duration   0.3716   282.4850 10.3672   0.00180

Kết thúc cập nhật vào ngày 9 tháng 3 năm 2011 .


cho bảng clustkết quả là:

rows  reads CPU   Elapsed 
----- ----- ----- --------
1503  4827  31ms  327ms
401   1241  0ms   242ms
2700  8372  0ms   410ms
0     3     0ms   0ms
2953  9060  47ms  213ms
0     0     0ms   0ms

Cập nhật ngày 9 tháng 3 năm 2011 : cmd.CommandText = "select * from clust where group between @id and @id+1000";

  • 721 Hàng có> 0 CPU và ảnh hưởng đến hơn 0 hàng
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1001      69788    6056         -
Cpu            15        468      38   0.00782
Reads        3194     227018   20457   3.37618
Writes          0          0       0       0.0
Duration   0.3949   159.6223 11.5699   0.00214

Kết thúc cập nhật vào ngày 9 tháng 3 năm 2011 .


CHỌN VỚI hiệu suất THAM GIA

cmd.CommandText = "select * from heap/clust h join keys k on h.group = k.group where h.group between @id and @id+1000";


Kết quả của điểm chuẩn này là dành cho heap:

873 Hàng có> 0 CPU và ảnh hưởng đến hơn 0 hàng

Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1009       4170    1683         -
Cpu            15         47      18   0.01175
Reads        2145       5518    2867   1.79246
Writes          0          0       0   0.00000
Duration   0.8215   131.9583  1.9095   0.00123

Kết quả của điểm chuẩn này là dành cho clust:

865 Hàng có> 0 CPU và ảnh hưởng đến hơn 0 hàng

Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1000       4143    1685         -
Cpu            15         47      18   0.01193
Reads        5320      18690    8237   4.97813
Writes          0          0       0   0.00000
Duration   0.9699    20.3217  1.7934   0.00109

CẬP NHẬT hiệu suất

Lô truy vấn thứ hai là các câu lệnh cập nhật:

update heap/clust set amount = amount + 0 where group between 5678910 and 5679410
update heap/clust set amount = amount + 0 where group between 6234567 and 6234967
update heap/clust set amount = amount + 0 where group between 6455429 and 6455729
update heap/clust set amount = amount + 0 where group between 6655429 and 6655729
update heap/clust set amount = amount + 0 where group between 6955429 and 6955729
update heap/clust set amount = amount + 0 where group between 7195542 and 7155729

kết quả của điểm chuẩn này cho heap:

rows  reads CPU   Elapsed 
----- ----- ----- -------- 
1503  3013  31ms  175ms
401   806   0ms   22ms
2700  5409  47ms  100ms
0     3     0ms   0ms
2953  5915  31ms  88ms
0     0     0ms   0ms

Cập nhật ngày 9 tháng 3 năm 2011 : cmd.CommandText = "update heap set amount = amount + @id where group between @id and @id+1000";

  • 811 Hàng có> 0 CPU và ảnh hưởng đến hơn 0 hàng
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1001      69788    5598       811         
Cpu            15        873      56   0.01199
Reads        2080     167593   11809   2.11217
Writes          0       1687     121   0.02170
Duration   0.6705   514.5347 17.2041   0.00344

Kết thúc cập nhật vào ngày 9 tháng 3 năm 2011 .


kết quả của điểm chuẩn này cho clust:

rows  reads CPU   Elapsed 
----- ----- ----- -------- 
1503  9126  16ms  35ms
401   2444  0ms   4ms
2700  16385 31ms  54ms
0     3     0ms   0ms 
2953  17919 31ms  35ms
0     0     0ms   0ms

Cập nhật ngày 9 tháng 3 năm 2011 : cmd.CommandText = "update clust set amount = amount + @id where group between @id and @id+1000";

  • 853 Hàng có> 0 CPU và ảnh hưởng đến hơn 0 hàng
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1001      69788    5420         -
Cpu            15        594      50   0.01073
Reads        6226     432237   33597   6.20450
Writes          0       1730     110   0.01971
Duration   0.9134   193.7685  8.2919   0.00155

Kết thúc cập nhật vào ngày 9 tháng 3 năm 2011 .


XÓA điểm chuẩn

lô truy vấn thứ ba tôi chạy là xóa các câu lệnh

delete heap/clust where group between 5678910 and 5679410
delete heap/clust where group between 6234567 and 6234967
delete heap/clust where group between 6455429 and 6455729
delete heap/clust where group between 6655429 and 6655729
delete heap/clust where group between 6955429 and 6955729
delete heap/clust where group between 7195542 and 7155729

Kết quả của điểm chuẩn này cho heap:

rows  reads CPU   Elapsed 
----- ----- ----- -------- 
1503  10630 62ms  179ms
401   2838  0ms   26ms
2700  19077 47ms  87ms
0     4     0ms   0ms
2953  20865 62ms  196ms
0     4     0ms   9ms

Cập nhật ngày 9 tháng 3 năm 2011 : cmd.CommandText = "delete heap where group between @id and @id+1000";

  • 724 Hàng có> 0 CPU và ảnh hưởng đến hơn 0 hàng
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts     192      69788    4781         -
Cpu            15        499      45   0.01247
Reads         841     307958   20987   4.37880
Writes          2       1819     127   0.02648
Duration   0.3775  1534.3383 17.2412   0.00349

Kết thúc cập nhật vào ngày 9 tháng 3 năm 2011 .


kết quả của điểm chuẩn này cho clust:

rows  reads CPU   Elapsed 
----- ----- ----- -------- 
1503  9228  16ms  55ms
401   3681  0ms   50ms
2700  24644 46ms  79ms
0     3     0ms   0ms
2953  26955 47ms  92ms
0     3     0ms   0ms

Cập nhật ngày 9 tháng 3 năm 2011 :

cmd.CommandText = "delete clust where group between @id and @id+1000";

  • 751 Hàng có> 0 CPU và ảnh hưởng đến hơn 0 hàng
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts     144      69788    4648         -
Cpu            15        764      56   0.01538
Reads         989     458467   30207   6.48490
Writes          2       1830     127   0.02694
Duration   0.2938  2512.1968 24.3714   0.00555

Kết thúc cập nhật vào ngày 9 tháng 3 năm 2011 .


Điểm chuẩn INSERT

Phần cuối cùng của điểm chuẩn là việc thực hiện các câu lệnh chèn.

chèn vào các giá trị heap / clust (...) (...), (...), (...), (...), (...), (...)


Kết quả của điểm chuẩn này cho heap:

rows  reads CPU   Elapsed 
----- ----- ----- -------- 
6     38    0ms   31ms

Cập nhật ngày 9 tháng 3 năm 2011 :

string str = @"insert into heap (group, currency, year, period, domain_id, mtdAmount, mtdAmount, ytdAmount, amount, ytd_restated, restated, auditDate, auditUser)
                    values";

                    for (int x = 0; x < 999; x++)
                    {
                        str += string.Format(@"(@id + {0}, 'EUR', 2012, 2, 0, 100, 100, 1000 + @id,1000, 1000,1000, current_timestamp, 'test'),  ", x);
                    }
                    str += string.Format(@"(@id, 'CAD', 2012, 2, 0, 100, 100, 1000 + @id,1000, 1000,1000, current_timestamp, 'test') ", 1000);

                    cmd.CommandText = str;
  • 912 câu lệnh có> 0 CPU
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1000       1000    1000         -
Cpu            15       2138      25   0.02500
Reads        5212       7069    6328   6.32837
Writes         16         34      22   0.02222
Duration   1.6336   293.2132  4.4009   0.00440

Kết thúc cập nhật vào ngày 9 tháng 3 năm 2011 .


Kết quả của điểm chuẩn này cho clust:

rows  reads CPU   Elapsed 
----- ----- ----- -------- 
6     50    0ms   18ms

Cập nhật ngày 9 tháng 3 năm 2011 :

string str = @"insert into clust (group, currency, year, period, domain_id, mtdAmount, mtdAmount, ytdAmount, amount, ytd_restated, restated, auditDate, auditUser)
                    values";

                    for (int x = 0; x < 999; x++)
                    {
                        str += string.Format(@"(@id + {0}, 'EUR', 2012, 2, 0, 100, 100, 1000 + @id,1000, 1000,1000, current_timestamp, 'test'),  ", x);
                    }
                    str += string.Format(@"(@id, 'CAD', 2012, 2, 0, 100, 100, 1000 + @id,1000, 1000,1000, current_timestamp, 'test') ", 1000);

                    cmd.CommandText = str;
  • 946 câu lệnh có> 0 CPU
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1000       1000    1000         -      
Cpu            15       2403      21   0.02157
Reads        6810       8997    8412   8.41223
Writes         16         25      19   0.01942
Duration   1.5375   268.2571  6.1463   0.00614

Kết thúc cập nhật vào ngày 9 tháng 3 năm 2011 .


Kết luận

Mặc dù có nhiều lần đọc logic hơn đang diễn ra khi truy cập vào bảng với chỉ mục được nhóm & không được bao gồm (trong khi sử dụng chỉ mục không được bao gồm), kết quả thực hiện là:

  • Các câu lệnh CHỌN có thể so sánh được
  • Các câu lệnh CẬP NHẬT nhanh hơn với một chỉ mục được nhóm
  • Các câu lệnh XÓA nhanh hơn với một chỉ mục được nhóm
  • Các câu lệnh INSERT nhanh hơn với một chỉ mục được nhóm

Tất nhiên điểm chuẩn của tôi rất hạn chế trên một loại bảng cụ thể và với một bộ truy vấn rất hạn chế, nhưng tôi nghĩ rằng dựa trên thông tin này, chúng tôi có thể bắt đầu nói rằng việc tạo một chỉ mục được nhóm trên bảng của bạn hầu như luôn luôn tốt hơn.

Cập nhật ngày 9 tháng 3 năm 2011 :

Như chúng ta có thể thấy từ các kết quả được thêm vào, các kết luận về các bài kiểm tra giới hạn là không chính xác trong mọi trường hợp.

Thời lượng có trọng số

Các kết quả hiện chỉ ra rằng các câu lệnh duy nhất được hưởng lợi từ chỉ mục được nhóm là các câu lệnh cập nhật. Các báo cáo khác chậm hơn khoảng 30% trên bảng với chỉ số được nhóm.

Một số biểu đồ bổ sung trong đó tôi đã vẽ thời lượng có trọng số cho mỗi truy vấn cho heap vs clust. Heap thời lượng có trọng số so với cụm cho Chọn

Thời lượng có trọng số heap vs clustered cho Tham gia

Heap thời lượng có trọng số so với cụm được cập nhật

Heap thời lượng có trọng số so với cụm cho Xóa

Như bạn có thể thấy hồ sơ hiệu suất cho các câu lệnh chèn khá thú vị. Các đột biến được gây ra bởi một vài điểm dữ liệu mất nhiều thời gian hơn để hoàn thành. Heap thời lượng có trọng số so với cụm cho Chèn

Kết thúc cập nhật vào ngày 9 tháng 3 năm 2011 .


@Martin Tôi sẽ thử chạy cái này trên một máy chủ có vài bảng với 500 triệu bản ghi khi tôi tìm thấy một thời gian vào tuần tới.
Filip De Vos

Tôi nghi ngờ tính chính xác của bài kiểm tra này. Một số phần cần chú ý nghiêm túc, chẳng hạn như hiệu suất INSERT tuyên bố chỉ số được nhóm nhanh hơn - có nhiều lần đọc hơn trong phiên bản CLUST, nhưng thời gian trôi qua thì ít hơn. Cá nhân tôi đã bỏ qua thời gian trôi qua trong vòng 10 giây tính bằng (biến thiên thời gian) - nó có nghĩa là ít hơn số lần đọc.

Hãy xem Cuộc tranh luận về Chỉ số phân cụm của Kimberly Tripp, nơi cô giải thích lý do tại sao hầu hết (nếu không phải tất cả) các hoạt động với một bảng được nhóm nhanh hơn so với một đống - một số trái với kết quả của bạn ...
marc_s

1
@Martin, @Richard, @marc_s. Tôi đang làm việc trên một tiêu chuẩn nghiêm trọng hơn ngay bây giờ. Tôi hy vọng có thể thêm kết quả sau ngày hôm nay.
Filip De Vos

1
@Filip - Chà! Bạn chắc chắn xứng đáng với tiền thưởng cho tất cả các công việc khó khăn mà bạn đã đưa vào câu trả lời này. Mặc dù bạn hoàn toàn chỉ ra rằng đây là một điểm chuẩn trên một loại bảng cụ thể với một bộ truy vấn rất hạn chế và số dặm sẽ không nghi ngờ gì khác nhau.
Martin Smith

12

Như Kimberly Tripp - Nữ hoàng lập chỉ mục - giải thích khá độc đáo trong bài đăng trên blog của mình Cuộc tranh luận về chỉ số cụm tiếp tục ... , có một khóa phân cụm trên bảng cơ sở dữ liệu tăng tốc tất cả các hoạt động - không chỉ SELECT.

CHỌN thường chậm hơn trên một đống so với bảng phân cụm, miễn là bạn chọn một khóa phân cụm tốt - một cái gì đó giống như một INT IDENTITY. Nếu bạn sử dụng khóa phân cụm thực sự xấu, như GUID hoặc khóa tổng hợp có nhiều thành phần có độ dài thay đổi, thì chỉ sau đó, một đống có thể nhanh hơn. Nhưng trong trường hợp đó, bạn thực sự cần phải dọn sạch thiết kế cơ sở dữ liệu của mình ngay từ đầu ...

Vì vậy, nói chung, tôi không nghĩ rằng có bất kỳ điểm nào trong một đống - chọn một khóa phân cụm tốt, hữu ích và bạn nên được hưởng lợi ở tất cả các khía cạnh.


3
Đây là một câu trả lời không. Martin khá vững chắc trên SQL Server; câu hỏi nhằm mục đích nhận được kết quả đã được kiểm tra trong thế giới thực từ kiểm tra hiệu suất, chứ không phải lý thuyết.

Bài báo Kimberly Tripp được liên kết có hiệu quả giả định tất cả các chỉ mục không bao gồm đang bao trùm. Nếu đó là trường hợp, thì sẽ không có tra cứu, và lợi thế của heap trong tra cứu sẽ bị phủ nhận. Tuy nhiên, đó không phải là một thế giới mà hầu hết chúng ta sống. Trong các trường hợp của chúng tôi, cố gắng thiết kế tất cả hoặc hầu hết các chỉ mục không bao gồm của chúng tôi để bao gồm sẽ tạo ra các vấn đề của riêng nó.

@ dbaguy52: tại sao bạn nghĩ Kim Tripp giả định tất cả các chỉ số NC đang bao trùm? Tôi không thấy bất kỳ khái niệm nào về điều đó trong bài đăng trên blog của cô ấy ..... vui lòng giải thích chi tiết hơn điều gì khiến bạn tin rằng đó là trường hợp (hoặc đó là giả định của cô ấy)
marc_s

7

Chỉ tình cờ bắt gặp bài viết này từ Joe Chang giải quyết câu hỏi này. Dán kết luận của mình dưới đây.

Xem xét một bảng mà các chỉ mục có độ sâu 4, sao cho có một cấp độ gốc, 2 cấp độ trung gian và cấp độ lá. Chỉ mục tìm kiếm một khóa chỉ mục duy nhất (nghĩa là không có tra cứu khóa) sẽ tạo ra 4 IO logic (LIO). Bây giờ hãy xem xét nếu cần phải tra cứu chính. Nếu bảng có chỉ số cụm cũng có độ sâu 4, mỗi lần tra cứu khóa sẽ tạo ra 4 LIO. Nếu bảng là một đống, mỗi lần tra cứu khóa sẽ tạo ra 1 LIO. Trên thực tế, việc tra cứu khóa cho một đống rẻ hơn khoảng 20-30% so với tra cứu khóa cho một chỉ số được nhóm, không phải ở bất kỳ nơi nào gần với tỷ lệ LIO 4: 1.


1
Điều thú vị cần lưu ý là trích dẫn từ Joe Chang đã xác định lợi thế hiệu quả là 20-30% cho các đống dựa trên các giả định của anh ta, đó là khá nhiều lợi thế tương tự được xác định trong bản cập nhật ngày 9 tháng 3 cho bài viế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.