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

SQL, bảng số bổ trợ

Heh ... xin lỗi vì tôi trả lời bài viết cũ quá muộn. Và, đúng vậy, tôi phải trả lời vì câu trả lời phổ biến nhất (vào thời điểm đó, câu trả lời CTE đệ quy với liên kết đến 14 phương pháp khác nhau) trên chủ đề này là, ummm ... hiệu suất được thử thách nhiều nhất.

Đầu tiên, bài viết với 14 giải pháp khác nhau phù hợp để xem các phương pháp khác nhau để tạo bảng Numbers / Tally nhanh chóng nhưng như đã chỉ ra trong bài viết và trong chuỗi được trích dẫn, có một rất trích dẫn quan trọng ...

"Các đề xuất liên quan đến hiệu quả và hiệu suất thường mang tính chủ quan. Bất kể cách truy vấn đang được sử dụng, thiết bị triển khai vật lý sẽ xác định hiệu quả của truy vấn. Do đó, thay vì dựa vào các nguyên tắc thiên vị, bạn bắt buộc phải kiểm tra truy vấn và xác định truy vấn nào hoạt động tốt hơn."

Trớ trêu thay, bản thân bài báo chứa nhiều tuyên bố chủ quan và "hướng dẫn thiên vị", chẳng hạn như "một CTE đệ quy có thể tạo ra một danh sách số khá hiệu quả " "Đây là một phương pháp hiệu quả sử dụng vòng lặp WHILE từ một nhóm tin đăng bởi Itzik Ben-Gen " (mà tôi chắc rằng anh ấy đăng lên chỉ nhằm mục đích so sánh). Thôi nào các bạn ơi ... Chỉ cần nhắc đến cái tên hay của Itzik thôi cũng có thể khiến một số kẻ lười biếng thực sự sử dụng phương pháp kinh khủng đó. Tác giả nên thực hành (những) điều anh ấy giảng và nên thực hiện một thử nghiệm hiệu suất nhỏ trước khi đưa ra những tuyên bố không chính xác đến mức nực cười như vậy, đặc biệt là khi đối mặt với bất kỳ khả năng mở rộng nào.

Với suy nghĩ thực sự thực hiện một số thử nghiệm trước khi đưa ra bất kỳ tuyên bố chủ quan nào về những gì bất kỳ mã nào làm hoặc những gì ai đó "thích", đây là một số mã bạn có thể thực hiện thử nghiệm của riêng mình. Thiết lập hồ sơ cho SPID mà bạn đang chạy thử nghiệm từ đó và tự mình kiểm tra ... chỉ cần thực hiện "Tìm kiếm'n'Replace" của số 1000000 cho số "yêu thích" của bạn và xem ...

--===== Test for 1000000 rows ==================================
GO
--===== Traditional RECURSIVE CTE method
   WITH Tally (N) AS 
        ( 
         SELECT 1 UNION ALL 
         SELECT 1 + N FROM Tally WHERE N < 1000000 
        ) 
 SELECT N 
   INTO #Tally1 
   FROM Tally 
 OPTION (MAXRECURSION 0);
GO
--===== Traditional WHILE LOOP method
 CREATE TABLE #Tally2 (N INT);
    SET NOCOUNT ON;
DECLARE @Index INT;
    SET @Index = 1;
  WHILE @Index <= 1000000 
  BEGIN 
         INSERT #Tally2 (N) 
         VALUES (@Index);
            SET @Index = @Index + 1;
    END;
GO
--===== Traditional CROSS JOIN table method
 SELECT TOP (1000000)
        ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS N
   INTO #Tally3
   FROM Master.sys.All_Columns ac1
  CROSS JOIN Master.sys.ALL_Columns ac2;
GO
--===== Itzik's CROSS JOINED CTE method
   WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
        E02(N) AS (SELECT 1 FROM E00 a, E00 b),
        E04(N) AS (SELECT 1 FROM E02 a, E02 b),
        E08(N) AS (SELECT 1 FROM E04 a, E04 b),
        E16(N) AS (SELECT 1 FROM E08 a, E08 b),
        E32(N) AS (SELECT 1 FROM E16 a, E16 b),
   cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32)
 SELECT N
   INTO #Tally4
   FROM cteTally
  WHERE N <= 1000000;
GO
--===== Housekeeping
   DROP TABLE #Tally1, #Tally2, #Tally3, #Tally4;
GO

Trong khi chúng tôi đang ở đó, đây là những con số tôi nhận được từ SQL Profiler cho các giá trị 100, 1000, 10000, 100000 và 1000000 ...

SPID TextData                                 Dur(ms) CPU   Reads   Writes
---- ---------------------------------------- ------- ----- ------- ------
  51 --===== Test for 100 rows ==============       8     0       0      0
  51 --===== Traditional RECURSIVE CTE method      16     0     868      0
  51 --===== Traditional WHILE LOOP method CR      73    16     175      2
  51 --===== Traditional CROSS JOIN table met      11     0      80      0
  51 --===== Itzik's CROSS JOINED CTE method        6     0      63      0
  51 --===== Housekeeping   DROP TABLE #Tally      35    31     401      0

  51 --===== Test for 1000 rows =============       0     0       0      0
  51 --===== Traditional RECURSIVE CTE method      47    47    8074      0
  51 --===== Traditional WHILE LOOP method CR      80    78    1085      0
  51 --===== Traditional CROSS JOIN table met       5     0      98      0
  51 --===== Itzik's CROSS JOINED CTE method        2     0      83      0
  51 --===== Housekeeping   DROP TABLE #Tally       6    15     426      0

  51 --===== Test for 10000 rows ============       0     0       0      0
  51 --===== Traditional RECURSIVE CTE method     434   344   80230     10
  51 --===== Traditional WHILE LOOP method CR     671   563   10240      9
  51 --===== Traditional CROSS JOIN table met      25    31     302     15
  51 --===== Itzik's CROSS JOINED CTE method       24     0     192     15
  51 --===== Housekeeping   DROP TABLE #Tally       7    15     531      0

  51 --===== Test for 100000 rows ===========       0     0       0      0
  51 --===== Traditional RECURSIVE CTE method    4143  3813  800260    154
  51 --===== Traditional WHILE LOOP method CR    5820  5547  101380    161
  51 --===== Traditional CROSS JOIN table met     160   140     479    211
  51 --===== Itzik's CROSS JOINED CTE method      153   141     276    204
  51 --===== Housekeeping   DROP TABLE #Tally      10    15     761      0

  51 --===== Test for 1000000 rows ==========       0     0       0      0
  51 --===== Traditional RECURSIVE CTE method   41349 37437 8001048   1601
  51 --===== Traditional WHILE LOOP method CR   59138 56141 1012785   1682
  51 --===== Traditional CROSS JOIN table met    1224  1219    2429   2101
  51 --===== Itzik's CROSS JOINED CTE method     1448  1328    1217   2095
  51 --===== Housekeeping   DROP TABLE #Tally       8     0     415      0

Như bạn có thể thấy, phương pháp CTE đệ quy kém thứ hai chỉ sau Vòng lặp While cho Thời lượng và CPU và có áp suất bộ nhớ ở dạng đọc logic cao gấp 8 lần so với Vòng lặp Trong khi . Đó là RBAR trên steroid và nên tránh, bằng mọi giá, đối với bất kỳ tính toán hàng đơn lẻ nào cũng như Vòng lặp Trong khi nên tránh. Có những nơi mà đệ quy khá có giá trị nhưng đây KHÔNG PHẢI là một trong số chúng .

Với tư cách là một thanh phụ, ông Denny hoàn toàn có mặt trên ... một bảng Số vĩnh viễn hoặc Bảng đếm có kích thước chính xác là cách để áp dụng cho hầu hết mọi thứ. Kích thước chính xác có nghĩa là gì? Hầu hết mọi người sử dụng bảng Tally để tạo ngày tháng hoặc để thực hiện phân chia trên VARCHAR (8000). Nếu bạn tạo một bảng Tally 11.000 hàng với chỉ số được nhóm chính xác trên "N", bạn sẽ có đủ hàng để tạo ra các ngày có giá trị hơn 30 năm (Tôi làm việc với các khoản thế chấp một chút nên 30 năm là một con số quan trọng đối với tôi ) và chắc chắn đủ để xử lý phân tách VARCHAR (8000). Tại sao "kích thước phù hợp" lại quan trọng như vậy? Nếu bảng Tally được sử dụng nhiều, nó dễ dàng nằm gọn trong bộ nhớ đệm, giúp nó hoạt động nhanh chóng mà không gây nhiều áp lực cho bộ nhớ.

Cuối cùng nhưng không kém phần quan trọng, mọi người đều biết rằng nếu bạn tạo một bảng Tally vĩnh viễn, bạn sử dụng phương pháp nào để tạo nó không quan trọng vì 1) nó chỉ được tạo một lần và 2) nếu nó giống như một hàng 11.000 bảng, tất cả các phương thức sẽ chạy "đủ tốt". Vậy tại sao tất cả sự phẫn nộ về phía tôi về việc sử dụng phương pháp nào ???

Câu trả lời là một số anh chàng / cô gái nghèo không biết gì tốt hơn và chỉ cần hoàn thành công việc của mình có thể thấy một cái gì đó giống như phương pháp CTE đệ quy và quyết định sử dụng nó cho một thứ gì đó lớn hơn và được sử dụng thường xuyên hơn nhiều so với việc xây dựng bảng Tally vĩnh viễn và tôi đang cố gắng bảo vệ những người đó, máy chủ mà mã của họ chạy và công ty sở hữu dữ liệu trên những máy chủ đó . Phải ... đó là một vấn đề lớn. Nó cũng nên dành cho tất cả những người khác. Dạy cách làm đúng thay vì "đủ tốt". Thực hiện một số thử nghiệm trước khi đăng hoặc sử dụng nội dung nào đó từ một bài đăng hoặc cuốn sách ... trên thực tế, cuộc sống mà bạn tiết kiệm được có thể là của riêng bạn, đặc biệt nếu bạn nghĩ CTE đệ quy là cách để thực hiện một cái gì đó như thế này.;-)

Cảm ơn đã lắng nghe ...



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. TSQL - Cách sử dụng GO bên trong khối BEGIN .. END?

  2. Làm cách nào để kích hoạt MSDTC trên SQL Server?

  3. Lấy dữ liệu từ quy trình được lưu trữ với Entity Framework

  4. Cách cài đặt SQL Server trên Linux

  5. SQL Server 2016:Sao lưu cơ sở dữ liệu