Database
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Database

Tại sao Trình tối ưu hóa không sử dụng Kiến thức nhóm đệm

SQL Server có một trình tối ưu hóa dựa trên chi phí sử dụng kiến ​​thức về các bảng khác nhau liên quan đến một truy vấn để tạo ra những gì nó quyết định là kế hoạch tối ưu nhất trong thời gian có sẵn cho nó trong quá trình biên dịch. Kiến thức này bao gồm bất kỳ chỉ mục nào tồn tại và kích thước của chúng và bất kỳ thống kê cột nào tồn tại. Một phần của việc tìm ra kế hoạch truy vấn tối ưu là cố gắng giảm thiểu số lần đọc vật lý cần thiết trong quá trình thực thi kế hoạch.

Một điều tôi đã được hỏi một vài lần là tại sao trình tối ưu hóa không xem xét những gì có trong vùng đệm SQL Server khi biên dịch kế hoạch truy vấn, vì chắc chắn điều đó có thể làm cho truy vấn thực thi nhanh hơn. Trong bài đăng này, tôi sẽ giải thích lý do tại sao.

Tìm ra nội dung nhóm đệm

Lý do đầu tiên khiến trình tối ưu hóa bỏ qua vùng đệm là một vấn đề không nhỏ khi tìm ra những gì có trong vùng đệm do cách tổ chức vùng đệm. Các trang tệp dữ liệu được kiểm soát trong vùng đệm bởi cấu trúc dữ liệu nhỏ được gọi là bộ đệm, theo dõi những thứ như (danh sách không đầy đủ):

  • ID của trang (số tệp:page-number-in-file)
  • Lần cuối cùng trang được tham chiếu (được người viết lười sử dụng để giúp triển khai thuật toán ít được sử dụng nhất nhằm tạo không gian trống khi cần thiết)
  • Vị trí bộ nhớ của trang 8KB trong vùng đệm
  • Trang có bẩn hay không (trang bẩn có các thay đổi trên trang đó mà chưa được ghi lại vào bộ nhớ lâu bền)
  • Đơn vị phân bổ mà trang thuộc về (giải thích ở đây) và ID đơn vị phân bổ có thể được sử dụng để tìm ra bảng và lập chỉ mục trang là một phần của

Đối với mỗi cơ sở dữ liệu có các trang trong vùng đệm, có một danh sách băm của các trang, theo thứ tự ID trang, có thể nhanh chóng tìm kiếm được để xác định xem một trang đã có trong bộ nhớ hay chưa hay phải thực hiện đọc vật lý. Tuy nhiên, không có gì dễ dàng cho phép SQL Server xác định phần trăm mức lá cho mỗi chỉ mục của bảng đã có trong bộ nhớ. Mã sẽ phải quét toàn bộ danh sách các vùng đệm cho cơ sở dữ liệu, tìm kiếm các vùng đệm ánh xạ các trang cho đơn vị phân bổ được đề cập. Và càng nhiều trang trong bộ nhớ cho cơ sở dữ liệu, quá trình quét sẽ mất nhiều thời gian hơn. Sẽ rất tốn kém nếu thực hiện như một phần của quá trình biên dịch truy vấn.

Nếu bạn quan tâm, tôi đã viết một bài đăng với một số mã T-SQL quét vùng đệm và đưa ra một số chỉ số, sử dụng DMV sys.dm_os_buffer_descriptors .

Tại sao việc sử dụng nội dung nhóm đệm lại nguy hiểm

Hãy giả sử * có * một cơ chế hiệu quả cao để xác định nội dung vùng đệm mà trình tối ưu hóa có thể sử dụng để giúp trình tối ưu hóa chọn chỉ mục nào sẽ sử dụng trong kế hoạch truy vấn. Giả thuyết tôi sẽ khám phá là nếu trình tối ưu hóa biết đủ chỉ mục kém hiệu quả hơn (lớn hơn) đã có trong bộ nhớ, so với chỉ mục hiệu quả nhất (nhỏ hơn) để sử dụng, nó sẽ chọn chỉ mục trong bộ nhớ vì nó sẽ giảm số lần đọc vật lý cần thiết và truy vấn sẽ chạy nhanh hơn.

Tình huống tôi sẽ sử dụng như sau:một bảng BigTable có hai chỉ mục không phân biệt, Index_A và Index_B, cả hai đều bao gồm hoàn toàn một truy vấn cụ thể. Truy vấn yêu cầu quét toàn bộ cấp độ lá của chỉ mục để truy xuất kết quả truy vấn. Bảng có 1 triệu hàng. Index_A có 200.000 trang ở cấp độ lá và Index_B có 1 triệu trang ở cấp độ lá, do đó, một quá trình quét hoàn chỉnh Index_B yêu cầu xử lý số trang nhiều hơn năm lần.

Tôi đã tạo ví dụ có sẵn này trên máy tính xách tay chạy SQL Server 2019 với 8 lõi xử lý, bộ nhớ 32 GB và đĩa trạng thái rắn. Mã như sau:

 TẠO BẢNG BigTable (c1 NHẬN DẠNG LỚN, c2 AS (c1 * 2), c3 CHAR (1500) DEFAULT 'a', c4 CHAR (5000) DEFAULT 'b'); ĐI CHÈN VÀO CÁC GIÁ TRỊ ĐỊNH VỊ BigTable; ĐI 1000000 TẠO CHỈ SỐ KHÔNG ĐIỀU CHỈNH_A TRÊN BigTable (c2) BAO GỒM (c3); - 5 bản ghi trên mỗi trang =200.000 trang / pre> 

Và sau đó, tôi tính thời gian cho các truy vấn theo mẫu:

 DBCC DROPCLEANBUFFERS; ĐI - Chỉ mục_A không có trong bộ nhớ FROM BigTable VỚI (INDEX (Index_A)); ĐI - thời gian CPU =312 mili giây, thời gian đã trôi qua =52 mili giây DBCC DROPCLEANBUFFERS; ĐI - Chỉ mục_B không có trong bộ nhớ - Thời gian CPU =2952 ms, thời gian đã trôi qua =2761 ms - Chỉ mục_B trong bộ nhớ 

Bạn có thể thấy khi không có chỉ mục nào ở trong bộ nhớ, Index_A dễ dàng là chỉ mục hiệu quả nhất để sử dụng, với thời gian truy vấn đã trôi qua là 764ms so với 2.761ms khi sử dụng Index_B và điều này cũng đúng khi cả hai chỉ mục đều ở trong bộ nhớ. Tuy nhiên, nếu Index_B nằm trong bộ nhớ và Index_A thì không, nếu truy vấn sử dụng Index_B (149ms) thì nó sẽ chạy nhanh hơn nếu sử dụng Index_A (764ms).

Bây giờ, hãy cho phép trình tối ưu hóa lựa chọn kế hoạch dựa trên những gì có trong vùng đệm…

Nếu Index_A chủ yếu không có trong bộ nhớ và Index_B hầu hết ở trong bộ nhớ, thì sẽ hiệu quả hơn nếu biên dịch kế hoạch truy vấn để sử dụng Index_B, cho một truy vấn chạy ngay lúc đó. Mặc dù Index_B lớn hơn và sẽ cần nhiều chu kỳ CPU hơn để quét qua, các lần đọc vật lý chậm hơn nhiều so với các chu kỳ CPU bổ sung, do đó, một kế hoạch truy vấn hiệu quả hơn sẽ giảm thiểu số lần đọc vật lý.

Đối số này chỉ đúng và kế hoạch truy vấn “sử dụng Index_B” chỉ hiệu quả hơn kế hoạch truy vấn “sử dụng Index_A”, nếu Index_B chủ yếu vẫn còn trong bộ nhớ và Index_A hầu như không có trong bộ nhớ. Ngay khi phần lớn Index_A nằm trong bộ nhớ, kế hoạch truy vấn “sử dụng Index_A” sẽ hiệu quả hơn và kế hoạch truy vấn “sử dụng Index_B” là lựa chọn sai.

Các tình huống khi kế hoạch “sử dụng Index_B” đã biên dịch kém hiệu quả hơn kế hoạch “sử dụng Index_A” dựa trên chi phí là (tổng quát hóa):

  • Index_A và Index_B đều nằm trong bộ nhớ:kế hoạch đã biên dịch sẽ lâu hơn gần ba lần
  • Không chỉ mục nào là nơi cư trú của bộ nhớ:kế hoạch đã biên dịch có thời gian lâu hơn 3,5 lần
  • Index_A là cư dân bộ nhớ còn Index_B thì không:tất cả các lần đọc vật lý do kế hoạch thực hiện đều không liên quan VÀ sẽ lâu hơn gấp 53 lần

Tóm tắt

Mặc dù trong bài tập suy nghĩ của chúng tôi, trình tối ưu hóa có thể sử dụng kiến ​​thức về vùng đệm để biên dịch truy vấn hiệu quả nhất ngay lập tức, nhưng đó sẽ là một cách nguy hiểm để thúc đẩy quá trình biên dịch kế hoạch vì sự biến động tiềm ẩn của nội dung vùng đệm, làm cho hiệu quả trong tương lai của kế hoạch đã lưu trong bộ nhớ cache rất không đáng tin cậy.

Hãy nhớ rằng, công việc của trình tối ưu hóa là nhanh chóng tìm ra một kế hoạch tốt, không nhất thiết phải là một kế hoạch tốt nhất cho 100% mọi trường hợp. Theo ý kiến ​​của tôi, trình tối ưu hóa SQL Server thực hiện đúng bằng cách bỏ qua nội dung thực tế của vùng đệm SQL Server và thay vào đó dựa vào các quy tắc chi phí khác nhau để tạo ra một kế hoạch truy vấn có khả năng hiệu quả nhất mọi lúc. .


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Kết nối với Vertica trong IRI Workbench

  2. Những gì tôi muốn thấy trong Amazon EC2 cho Quản lý cơ sở dữ liệu

  3. Huyền thoại về hiệu suất:Quá kích thước cột chuỗi

  4. SQL GROUP BY- 3 Mẹo dễ dàng để nhóm kết quả giống như một chuyên gia

  5. Lập hồ sơ dữ liệu:Khám phá chi tiết dữ liệu