Bảy lớp triển khai sắp xếp của SQL Server là:
- CQScanSortNew
- CQScanTopSortNew
- CQScanIndexSortNew
- CQScanPartitionSortNew (chỉ dành cho SQL Server 2014)
- CQScanInMemSortNew
- Trong bộ nhớ OLTP (Hekaton) thủ tục được biên dịch nguyên bản Top N Sort (chỉ dành cho SQL Server 2014)
- Trong bộ nhớ OLTP (Hekaton) thủ tục được biên dịch nguyên bản Sắp xếp chung (chỉ dành cho SQL Server 2014)
Bốn loại đầu tiên đã được đề cập trong phần một của bài viết này.
5. CQScanInMemSortNew
Lớp sắp xếp này có một số tính năng thú vị, một số trong số đó là duy nhất:
- Như tên cho thấy, nó luôn được sắp xếp hoàn toàn trong bộ nhớ; nó sẽ không bao giờ tràn sang tempdb
- Sắp xếp luôn được thực hiện bằng cách sử dụng quicksort qsort_s trong thư viện thời gian chạy C chuẩn MSVCR100
- Nó có thể thực hiện tất cả ba kiểu sắp xếp hợp lý:Chung, Đầu N và Sắp xếp Riêng biệt
- Nó có thể được sử dụng cho các loại mềm phân vùng cột theo cụm (xem phần 4 trong phần 1)
- Bộ nhớ mà nó sử dụng có thể được lưu vào bộ nhớ đệm cùng với gói thay vì được dành riêng trước khi thực thi
- Nó có thể được xác định là một loại trong bộ nhớ trong các kế hoạch thực thi
- Có thể sắp xếp tối đa 500 giá trị
- Nó không bao giờ được sử dụng cho các loại xây dựng chỉ mục (xem phần 3 trong phần 1)
CQScanInMemSortNew là một lớp sắp xếp mà bạn sẽ không gặp phải thường xuyên. Vì nó luôn sắp xếp trong bộ nhớ bằng thuật toán quicksort thư viện tiêu chuẩn, nó sẽ không phải là một lựa chọn tốt cho các tác vụ sắp xếp cơ sở dữ liệu chung. Trên thực tế, lớp sắp xếp này chỉ được sử dụng khi tất cả các đầu vào của nó là hằng số thời gian chạy (bao gồm cả tham chiếu @variable). Từ góc độ kế hoạch thực thi, điều đó có nghĩa là đầu vào cho toán tử Sắp xếp phải là Quét liên tục , như các ví dụ dưới đây chứng minh:
-- Regular Sort on system scalar functions SELECT X.i FROM ( SELECT @@TIMETICKS UNION ALL SELECT @@TOTAL_ERRORS UNION ALL SELECT @@TOTAL_READ UNION ALL SELECT @@TOTAL_WRITE ) AS X (i) ORDER BY X.i; -- Distinct Sort on constant literals WITH X (i) AS ( SELECT 3 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 2 ) SELECT DISTINCT X.i FROM X ORDER BY X.i; -- Top N Sort on variables, constants, and functions DECLARE @x integer = 1, @y integer = 2; SELECT TOP (1) X.i FROM ( VALUES (@x), (@y), (123), (@@CONNECTIONS) ) AS X (i) ORDER BY X.i;
Các kế hoạch thực hiện là:
Một ngăn xếp cuộc gọi điển hình trong quá trình sắp xếp được hiển thị bên dưới. Lưu ý lệnh gọi qsort_s trong thư viện MSVCR100:
Tất cả ba kế hoạch thực thi được hiển thị ở trên đều được sắp xếp trong bộ nhớ bằng cách sử dụng CQScanInMemSortNew với đầu vào đủ nhỏ để bộ nhớ sắp xếp được lưu vào bộ nhớ đệm. Thông tin này không được hiển thị theo mặc định trong các kế hoạch thực thi, nhưng nó có thể được tiết lộ bằng cách sử dụng cờ theo dõi không có tài liệu 8666. Khi cờ đó hoạt động, các thuộc tính bổ sung sẽ xuất hiện cho toán tử Sắp xếp:
Bộ đệm cache được giới hạn ở 62 hàng trong ví dụ này như được minh họa bên dưới:
-- Cache buffer limited to 62 rows SELECT X.i FROM ( VALUES (001),(002),(003),(004),(005),(006),(007),(008),(009),(010), (011),(012),(013),(014),(015),(016),(017),(018),(019),(020), (021),(022),(023),(024),(025),(026),(027),(028),(029),(030), (031),(032),(033),(034),(035),(036),(037),(038),(039),(040), (041),(042),(043),(044),(045),(046),(047),(048),(049),(050), (051),(052),(053),(054),(055),(056),(057),(058),(059),(060), (061),(062)--, (063) ) AS X (i) ORDER BY X.i;
Bỏ ghi chú mục cuối cùng trong tập lệnh đó để xem thuộc tính bộ đệm Sort cache thay đổi từ 1 thành 0:
Khi bộ đệm không được lưu trong bộ nhớ đệm, sắp xếp trong bộ nhớ phải cấp phát bộ nhớ khi nó khởi tạo và theo yêu cầu khi nó đọc các hàng từ đầu vào của nó. Khi bộ đệm được lưu trong bộ nhớ đệm có thể được sử dụng, công việc cấp phát bộ nhớ này sẽ tránh được.
Tập lệnh sau có thể được sử dụng để chứng minh rằng số lượng mục tối đa cho một CQScanInMemSortNew tốc độ nhanh trong bộ nhớ là 500:
SELECT X.i FROM ( VALUES (001),(002),(003),(004),(005),(006),(007),(008),(009),(010), (011),(012),(013),(014),(015),(016),(017),(018),(019),(020), (021),(022),(023),(024),(025),(026),(027),(028),(029),(030), (031),(032),(033),(034),(035),(036),(037),(038),(039),(040), (041),(042),(043),(044),(045),(046),(047),(048),(049),(050), (051),(052),(053),(054),(055),(056),(057),(058),(059),(060), (061),(062),(063),(064),(065),(066),(067),(068),(069),(070), (071),(072),(073),(074),(075),(076),(077),(078),(079),(080), (081),(082),(083),(084),(085),(086),(087),(088),(089),(090), (091),(092),(093),(094),(095),(096),(097),(098),(099),(100), (101),(102),(103),(104),(105),(106),(107),(108),(109),(110), (111),(112),(113),(114),(115),(116),(117),(118),(119),(120), (121),(122),(123),(124),(125),(126),(127),(128),(129),(130), (131),(132),(133),(134),(135),(136),(137),(138),(139),(140), (141),(142),(143),(144),(145),(146),(147),(148),(149),(150), (151),(152),(153),(154),(155),(156),(157),(158),(159),(160), (161),(162),(163),(164),(165),(166),(167),(168),(169),(170), (171),(172),(173),(174),(175),(176),(177),(178),(179),(180), (181),(182),(183),(184),(185),(186),(187),(188),(189),(190), (191),(192),(193),(194),(195),(196),(197),(198),(199),(200), (201),(202),(203),(204),(205),(206),(207),(208),(209),(210), (211),(212),(213),(214),(215),(216),(217),(218),(219),(220), (221),(222),(223),(224),(225),(226),(227),(228),(229),(230), (231),(232),(233),(234),(235),(236),(237),(238),(239),(240), (241),(242),(243),(244),(245),(246),(247),(248),(249),(250), (251),(252),(253),(254),(255),(256),(257),(258),(259),(260), (261),(262),(263),(264),(265),(266),(267),(268),(269),(270), (271),(272),(273),(274),(275),(276),(277),(278),(279),(280), (281),(282),(283),(284),(285),(286),(287),(288),(289),(290), (291),(292),(293),(294),(295),(296),(297),(298),(299),(300), (301),(302),(303),(304),(305),(306),(307),(308),(309),(310), (311),(312),(313),(314),(315),(316),(317),(318),(319),(320), (321),(322),(323),(324),(325),(326),(327),(328),(329),(330), (331),(332),(333),(334),(335),(336),(337),(338),(339),(340), (341),(342),(343),(344),(345),(346),(347),(348),(349),(350), (351),(352),(353),(354),(355),(356),(357),(358),(359),(360), (361),(362),(363),(364),(365),(366),(367),(368),(369),(370), (371),(372),(373),(374),(375),(376),(377),(378),(379),(380), (381),(382),(383),(384),(385),(386),(387),(388),(389),(390), (391),(392),(393),(394),(395),(396),(397),(398),(399),(400), (401),(402),(403),(404),(405),(406),(407),(408),(409),(410), (411),(412),(413),(414),(415),(416),(417),(418),(419),(420), (421),(422),(423),(424),(425),(426),(427),(428),(429),(430), (431),(432),(433),(434),(435),(436),(437),(438),(439),(440), (441),(442),(443),(444),(445),(446),(447),(448),(449),(450), (451),(452),(453),(454),(455),(456),(457),(458),(459),(460), (461),(462),(463),(464),(465),(466),(467),(468),(469),(470), (471),(472),(473),(474),(475),(476),(477),(478),(479),(480), (481),(482),(483),(484),(485),(486),(487),(488),(489),(490), (491),(492),(493),(494),(495),(496),(497),(498),(499),(500) --, (501) ) AS X (i) ORDER BY X.i;
Một lần nữa, bỏ ghi chú mục cuối cùng để xem Bộ nhớ trong Sắp xếp thay đổi thuộc tính từ 1 thành 0. Khi điều này xảy ra, CQScanInMemSortNew được thay thế bằng CQScanSortNew (xem phần 1) hoặc CQScanTopSortNew (phần 2). Không phải CQScanInMemSortNew Tất nhiên, sắp xếp vẫn có thể được thực hiện trong bộ nhớ, nó chỉ sử dụng một thuật toán khác và được phép tràn sang tempdb nếu cần.
6. Thủ tục lưu trữ trong bộ nhớ OLTP được biên dịch nguyên bản Top N Sắp xếp
Việc triển khai hiện tại của thủ tục lưu trữ trong bộ nhớ OLTP (tên mã trước đây là Hekaton) sử dụng một hàng đợi ưu tiên theo sau là qsort_s cho N Sắp xếp hàng đầu, khi các điều kiện sau được đáp ứng:
- Truy vấn chứa TOP (N) với mệnh đề ORDER BY
- Giá trị của N là một hằng số (không phải là một biến)
- N có giá trị lớn nhất là 8192; Mặc du
- Sự hiện diện của các liên kết hoặc tổng hợp có thể làm giảm giá trị 8192 như được ghi lại ở đây
Đoạn mã sau tạo một bảng Hekaton chứa 4000 hàng:
CREATE DATABASE InMemoryOLTP; GO -- Add memory optimized filegroup ALTER DATABASE InMemoryOLTP ADD FILEGROUP InMemoryOLTPFileGroup CONTAINS MEMORY_OPTIMIZED_DATA; GO -- Add file (adjust path if necessary) ALTER DATABASE InMemoryOLTP ADD FILE ( NAME = N'IMOLTP', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL12.SQL2014\MSSQL\DATA\IMOLTP.hkf' ) TO FILEGROUP InMemoryOLTPFileGroup; GO USE InMemoryOLTP; GO CREATE TABLE dbo.Test ( col1 integer NOT NULL, col2 integer NOT NULL, col3 integer NOT NULL, CONSTRAINT PK_dbo_Test PRIMARY KEY NONCLUSTERED HASH (col1) WITH (BUCKET_COUNT = 8192) ) WITH ( MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY ); GO -- Add numbers from 1-4000 using -- Itzik Ben-Gan's number generator WITH L0 AS (SELECT 1 AS c UNION ALL SELECT 1), L1 AS (SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B), L2 AS (SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B), L3 AS (SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B), L4 AS (SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B), L5 AS (SELECT 1 AS c FROM L4 AS A CROSS JOIN L4 AS B), Nums AS (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS n FROM L5) INSERT dbo.Test (col1, col2, col3) SELECT N.n, ABS(CHECKSUM(NEWID())), ABS(CHECKSUM(NEWID())) FROM Nums AS N WHERE N.n BETWEEN 1 AND 4000;
Tập lệnh tiếp theo tạo Sắp xếp N hàng đầu phù hợp trong một quy trình được lưu trữ được biên dịch nguyên bản:
-- Natively-compiled Top N Sort stored procedure CREATE PROCEDURE dbo.TestP WITH EXECUTE AS OWNER, SCHEMABINDING, NATIVE_COMPILATION AS BEGIN ATOMIC WITH ( TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english' ) SELECT TOP (2) T.col2 FROM dbo.Test AS T ORDER BY T.col2 END; GO EXECUTE dbo.TestP;
Kế hoạch thực hiện ước tính là:
Một ngăn xếp cuộc gọi được ghi lại trong quá trình thực thi hiển thị chèn vào hàng đợi ưu tiên đang được tiến hành:
Sau khi xây dựng hàng đợi ưu tiên hoàn tất, ngăn xếp cuộc gọi tiếp theo hiển thị một lần chuyển cuối cùng qua quicksort thư viện tiêu chuẩn:
xtp_p_ * thư viện hiển thị trong các ngăn xếp cuộc gọi đó là dll được biên dịch nguyên bản cho thủ tục được lưu trữ, với mã nguồn được lưu trên phiên bản SQL Server cục bộ. Mã nguồn được tạo tự động từ định nghĩa thủ tục được lưu trữ. Ví dụ:tệp C cho thủ tục được lưu trữ gốc này chứa đoạn sau:
Điều này gần như chúng ta có thể có được quyền truy cập vào mã nguồn SQL Server.
7. Thủ tục lưu trữ trong bộ nhớ OLTP được biên dịch nguyên bản Sắp xếp
Các quy trình được biên dịch tự nhiên hiện không hỗ trợ Sắp xếp riêng biệt, nhưng sắp xếp chung không riêng biệt được hỗ trợ mà không có bất kỳ hạn chế nào về kích thước của tập hợp. Để chứng minh, trước tiên, chúng tôi sẽ thêm 6.000 hàng vào bảng thử nghiệm, tạo ra tổng số 10.000 hàng:
WITH L0 AS (SELECT 1 AS c UNION ALL SELECT 1), L1 AS (SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B), L2 AS (SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B), L3 AS (SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B), L4 AS (SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B), L5 AS (SELECT 1 AS c FROM L4 AS A CROSS JOIN L4 AS B), Nums AS (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS n FROM L5) INSERT dbo.Test (col1, col2, col3) SELECT N.n, ABS(CHECKSUM(NEWID())), ABS(CHECKSUM(NEWID())) FROM Nums AS N WHERE N.n BETWEEN 4001 AND 10000;
Bây giờ chúng ta có thể loại bỏ quy trình kiểm tra trước đó (hiện không thể thay đổi các quy trình được biên dịch nguyên bản) và tạo một quy trình mới thực hiện một loại thông thường (không phải top-n) trong số 10.000 hàng:
DROP PROCEDURE dbo.TestP; GO CREATE PROCEDURE dbo.TestP WITH EXECUTE AS OWNER, SCHEMABINDING, NATIVE_COMPILATION AS BEGIN ATOMIC WITH ( TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english' ) SELECT T.col2 FROM dbo.Test AS T ORDER BY T.col2 END; GO EXECUTE dbo.TestP;
Kế hoạch thực hiện ước tính là:
Theo dõi việc thực thi sắp xếp này cho thấy rằng nó bắt đầu bằng cách tạo nhiều lần chạy được sắp xếp nhỏ bằng cách sử dụng lại quicksort của thư viện tiêu chuẩn:
Khi quá trình đó hoàn tất, các lần chạy đã sắp xếp sẽ được hợp nhất, sử dụng lược đồ hàng đợi ưu tiên:
Một lần nữa, mã nguồn C cho quy trình hiển thị một số chi tiết:
Tóm tắt Phần 2
- CQScanInMemSortNew luôn luôn là một mạch nhanh trong bộ nhớ. Nó được giới hạn trong 500 hàng từ một Quét liên tục và có thể lưu vào bộ nhớ sắp xếp của nó cho các đầu vào nhỏ. Một loại có thể được xác định là CQScanInMemSortNew sắp xếp bằng cách sử dụng các thuộc tính kế hoạch thực thi được hiển thị bởi cờ theo dõi 8666.
- Top N Sort được biên dịch gốc Hekaton yêu cầu giá trị chữ không đổi cho N <=8192 và sắp xếp bằng cách sử dụng hàng đợi ưu tiên theo sau là nhanh chuẩn
- General Sort được biên dịch gốc Hekaton có thể sắp xếp bất kỳ số lượng hàng nào, sử dụng quicksort của thư viện tiêu chuẩn để tạo ra các lần sắp xếp và sắp xếp hợp nhất hàng ưu tiên để kết hợp các lần chạy. Nó không hỗ trợ Phân loại riêng biệt.