Mysql chọn mỗi ngày trong phạm vi

Tôi có một trường hợp sử dụng phổ biến khi tôi cần chuyển đổi phạm vi ngày thành một tập hợp các hàng trong bảng SQL Server. Ví dụ: tôi có một bản ghi nói rằng một nhân viên đã nghỉ lễ từ 2020-08-01 đến 2020-08-20. Hàng đơn này cần được chuyển đổi thành 20 hàng, một hàng cho mỗi ngày của kỳ nghỉ. Làm cách nào tôi có thể thực hiện việc này một cách nhanh chóng và có thể mở rộng, vì các bảng của tôi chứa hàng nghìn bản ghi có thể dẫn đến hàng triệu hàng ở đầu ra?

Dung dịch

Chuyển đổi phạm vi ngày (hoặc bất kỳ loại phạm vi nào khác) thành một tập hợp các hàng là một yêu cầu phổ biến. Ví dụ: hệ thống nguồn cung cấp các hàng có ngày bắt đầu và ngày kết thúc trong một khoảng thời gian cụ thể, nhưng trong cơ sở dữ liệu của bạn, bạn cần một bảng giao dịch có một hàng cho mỗi ngày, vì điều này đơn giản hóa việc tính toán. Ví dụ, bạn có thể lọc ra các ngày cuối tuần và ngày lễ dễ dàng hơn nhiều so với khi bạn chỉ sử dụng ngày bắt đầu và ngày kết thúc của khoảng thời gian

Thông thường, thuật ngữ "bùng nổ bảng" được sử dụng vì một tập hợp nhỏ các phạm vi có thể dẫn đến một lượng lớn hàng. Nếu bạn có một hàng với 2020-01-01 là ngày bắt đầu và 2020-12-31 là ngày kết thúc, điều này sẽ dẫn đến 366 hàng. Hãy tưởng tượng bạn cần thực hiện phép tính tương tự cho hàng triệu khách hàng. Vì đầu ra có thể lớn nên điều quan trọng là giải pháp phải nhanh và có thể mở rộng. Điều này loại bỏ các vòng lặp và con trỏ trong T-SQL, vì chúng dựa trên hàng và không phù hợp với khối lượng hàng lớn. Các thuật ngữ khác bao gồm "starbursting" hoặc "unpacking một mối quan hệ trong một khoảng thời gian"

Trong mẹo này, một giải pháp được trình bày bằng cách sử dụng "bảng số", đôi khi còn được gọi là "bảng kiểm đếm". Để biết thêm thông tin cơ bản về loại bảng này, hãy xem các mẹo tuyệt vời này của Aaron Bertrand

  • Giải thích về bảng số máy chủ SQL - Phần 1
  • Giải thích về bảng số máy chủ SQL - Phần 2

Mẹo Hàm máy chủ SQL để trả về một phạm vi ngày thực hiện điều gì đó tương tự, nhưng sử dụng CTE đệ quy không thể mở rộng và cũng có giới hạn về số lần truy cập tối đa

Dữ liệu mẫu

Với câu lệnh SQL sau, chúng ta có thể tạo một bảng đơn giản để chứa dữ liệu mẫu

CREATE TABLE dbo.EmployeeHoliday
(EmployeeID VARCHAR(10) NOT NULL
,StartDate DATE NOT NULL
,EndDate DATE NOT NULL);

Hãy chèn 2 hàng vào bảng đó. Hai nhân viên đang đi nghỉ, cả ngày bắt đầu và ngày kết thúc

INSERT INTO dbo.EmployeeHoliday
SELECT [EmployeeID] = 'A', [StartDate] = '2020-06-01', [EndDate] = '2020-06-05'
UNION ALL
SELECT 'B','2020-12-15','2020-12-31';

Mysql chọn mỗi ngày trong phạm vi

Đây là kết quả cuối cùng mong muốn, một hàng cho mỗi ngày trong phạm vi ngày bắt đầu và ngày kết thúc

Mysql chọn mỗi ngày trong phạm vi

Tạo bảng số máy chủ SQL

Có nhiều phương pháp khác nhau để tạo bảng số, chẳng hạn như nối chéo hai tập hợp lớn lại với nhau (hãy xem mẹo của Aaron nếu bạn quan tâm đến các ví dụ), nhưng bạn cũng có thể tạo bảng "ảo" bằng cách sử dụng các biểu thức bảng phổ biến ( . Cú pháp sau đây được đặt ra bởi Itzik Ben-Gan, một bậc thầy về T-SQL

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 (SELECT NULL)) FROM E32)
SELECT N
FROM cteTally
WHERE N <= 10000;

Trong CTE E00 đầu tiên, hai hàng được nối với nhau. Trong CTE E02 tiếp theo, CTE đầu tiên này được nối chéo với chính nó. Điều này mang lại cho chúng tôi 4 hàng. Quá trình này được lặp lại một vài lần. CTE E32 cuối cùng sẽ trả về 2^32 hàng, đây cũng là số cao nhất mà một số nguyên có thể chứa trong SQL Server. Nhưng CTE này chỉ trả về các hàng có giá trị 1

Mysql chọn mỗi ngày trong phạm vi

Sử dụng chức năng cửa sổ ROW_NUMBER, chúng ta có thể gán số cho mỗi hàng. Đối với ORDER BY trong mệnh đề OVER, chúng ta sử dụng truy vấn con (SELECT NULL). Thủ thuật này SQL Server không sắp xếp tập dữ liệu. Nếu vậy, nó có thể là một vấn đề hiệu suất nghiêm trọng. Chạy toàn bộ câu lệnh SQL sẽ trả về một số thứ tự duy nhất cho mỗi hàng, bắt đầu bằng số 1

Mysql chọn mỗi ngày trong phạm vi

Tạo bảng một triệu hàng chỉ mất vài giây trên máy của tôi. Nhưng trong trường hợp sử dụng này, chúng tôi cần ngày tháng, không phải số. Chúng ta có thể chuyển đổi các số thành ngày bằng cách sử dụng hàm DATEADD. Câu lệnh SQL bây giờ trở thành

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 (SELECT NULL)) FROM E32)
SELECT ExplodedDate = DATEADD(DAY,N - 1,'2020-01-01')
FROM cteTally
WHERE N <= 366

Điều này sẽ tạo ra tất cả các ngày của năm 2020 (hãy nhớ rằng đó là một năm nhuận)

Mysql chọn mỗi ngày trong phạm vi

Khai thác phạm vi trong bảng số máy chủ SQL

Sử dụng bảng số (hoặc bảng ngày chính xác hơn), cuối cùng chúng ta có thể "bùng nổ" dữ liệu mẫu của mình. Chúng ta chỉ cần nối bảng kiểm đếm với bảng mẫu bằng phép nối dãy

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 (SELECT NULL)) FROM E32)
    ,DateRange AS
(
    SELECT ExplodedDate = DATEADD(DAY,N - 1,'2020-01-01')
    FROM cteTally
    WHERE N <= 366
)
SELECT *
FROM dbo.EmployeeHoliday eh
JOIN DateRange d ON d.ExplodedDate >= eh.[StartDate]
 AND d.ExplodedDate <= eh.[EndDate];

Điều này cho chúng ta tập kết quả mong muốn

Mysql chọn mỗi ngày trong phạm vi

Bắt đầu từ 2020-01-01 và chỉ mất 366 ngày là khá hạn chế đối với bảng ngày được tạo. Tuy nhiên, bạn có thể mở rộng các giới hạn này và điều này sẽ không ảnh hưởng quá nhiều đến hiệu suất. Hãy lấy 2000-01-01 làm điểm bắt đầu và tạo ngày tháng trong 100 năm (khoảng 365.000 hàng)

Mysql chọn mỗi ngày trong phạm vi

Truy vấn hiện kết thúc chỉ dưới 3 giây

Thử nghiệm với nhiều dữ liệu hơn

Hãy thực hiện trường hợp sử dụng tương tự, nhưng bây giờ sử dụng bảng Fact Internet Sales của kho dữ liệu AdventureWorks 2017. Chúng tôi sẽ phát nổ các ngày giữa ngày đặt hàng và ngày đáo hạn. Bảng thực tế chứa 60.398 hàng. Tập hợp kết quả được chia nhỏ sẽ chứa 785.174 hàng. Truy vấn SQL được điều chỉnh

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 (SELECT NULL)) FROM E32)
    ,DateRange AS
(
    SELECT ExplodedDate = DATEADD(DAY,N - 1,'2010-01-01')
    FROM cteTally
    WHERE N <= 5000
)
SELECT f.[SalesOrderNumber], f.[SalesOrderLineNumber], [f].[OrderDate], [f].[DueDate], d.[ExplodedDate]
INTO #Test
FROM [AdventureWorksDW2017].[dbo].[FactInternetSales] f
JOIN DateRange d ON d.ExplodedDate >= f.[OrderDate]
 AND d.ExplodedDate <= f.[DueDate];
 
SELECT COUNT(1) FROM #test;

Trong thử nghiệm này, tôi không trả lại các hàng về SSMS, vì việc hiển thị tất cả các hàng trong lưới sẽ mất quá nhiều thời gian. Thay vào đó, tôi đang chèn dữ liệu vào một bảng tạm thời và sau đó trả lại số lượng hàng từ bảng tạm thời này. Khai thác bảng Sự kiện Bán hàng qua Internet mất 20 giây trên máy của tôi

Mysql chọn mỗi ngày trong phạm vi

Cập nhật mẹo - Phương pháp thay thế

Trong các nhận xét, Jeff Moden đã đề xuất một cách khác để giải quyết vấn đề. Thay vì mã hóa cứng giới hạn thành 5.000 hàng, giới hạn được tính động bằng cách sử dụng DATEDIFF của đơn đặt hàng và ngày đến hạn. Giá trị này được áp dụng cho mệnh đề TOP, chỉ chọn số hàng của bảng kiểm đếm thực sự cần thiết. Các hàng kết quả sau đó được nối vào bảng thực tế bằng cách sử dụng CHÉO ÁP DỤNG, giải phóng phạm vi dữ liệu một cách hiệu quả

Đây là mã thích ứng

WITH
     H1(N) AS (SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) H0(N))
    ,cteTALLY(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM H1 a, H1 b, H1 c, H1 d, H1 e, H1 f, H1 g, H1 h)
SELECT
     f.SalesOrderNumber
    ,f.SalesOrderLineNumber
    ,f.OrderDate
    ,f.DueDate
    ,ExplodedDate = DATEADD(dd,t.N-1,f.OrderDate)
INTO #Test
FROM AdventureWorksDW2017.dbo.FactInternetSales f
CROSS APPLY (
    SELECT TOP (DATEDIFF(dd,f.OrderDate,f.DueDate) + 1)
        N
    FROM cteTally
    ORDER BY N
    ) t;

Ví dụ, giả sử rằng một hàng cụ thể của bảng Dữ liệu doanh số bán hàng qua Internet, số ngày giữa các ngày là 5 (có nghĩa là chúng ta cần 6 hàng được chia nhỏ, vì chúng ta cần bao gồm ngày đầu tiên). Điều này sẽ dẫn đến truy vấn con sau

SELECT TOP 6
 N
FROM cteTally
ORDER BY N

Điều này sẽ trả về 6 hàng của bảng kiểm đếm (1,2,3,4,5,6). Sử dụng ỨNG DỤNG CHÉO, 6 hàng này được nối với bảng thực tế, lặp lại hàng ban đầu của bảng thực tế 6 lần, nhưng với mỗi hàng, thêm (N-1) ngày vào ngày đặt hàng

Giải pháp hiệu quả hơn vì không có bảng làm việc nào được tạo trong cơ sở dữ liệu tempdb và bảng kiểm đếm không được cụ thể hóa trong bộ nhớ. Để biết thêm thông tin, hãy xem các ý kiến

Sự kết luận

Trong mẹo này, chúng ta đã thấy cách bạn có thể phân tách phạm vi ngày bằng cách sử dụng bảng "số". Đó là một kịch bản phổ biến để phân tích chuỗi thời gian chẳng hạn. Mã có thể được tối ưu hóa bằng cách sử dụng bảng ngày cố định thay vì tạo một bảng khi đang di chuyển. Tuy nhiên, mục đích của thủ thuật này là chỉ cho bạn các kỹ thuật tạo nhanh một bảng số lớn để cải thiện mã T-SQL của bạn bằng cách sử dụng logic dựa trên tập hợp

Bước tiếp theo
  • Nếu bạn chưa có, hãy xem mẹo của Aaron về những điều cơ bản của bảng số
    • Giải thích về bảng số máy chủ SQL - Phần 1
    • Giải thích về bảng số máy chủ SQL - Phần 2
  • Một lời giới thiệu tuyệt vời khác về bảng kiểm đếm của Jeff Moden. Bảng "Số" hoặc "Kiểm đếm". Nó là gì và nó thay thế vòng lặp như thế nào
  • Để biết thêm mẹo về T-SQL, hãy xem phần tổng quan này


Những bài viết liên quan

Chuyển đổi ngày và giờ bằng SQL Server

Hàm thời gian tiết kiệm ánh sáng ban ngày trong SQL Server

Hàm SQL Server để chuyển đổi ngày nguyên thành định dạng ngày giờ

Cộng và trừ ngày bằng cách sử dụng DATEADD trong SQL Server

Định dạng ngày máy chủ SQL với chức năng FORMAT

Tạo thứ nguyên ngày hoặc bảng lịch trong SQL Server

Các phương pháp hay nhất về DateTime của máy chủ SQL

Tạo Thứ nguyên ngày mở rộng cho Kho dữ liệu máy chủ SQL

Các hàm ngày và giờ của SQL Server với các ví dụ

Đơn giản hóa tính toán khoảng thời gian ngày trong SQL Server

Điền vào các ngày bị thiếu cho đầu ra truy vấn SQL Server

Hàm FORMAT của SQL Server cho Ngày, Số và Ngày của Tác nhân Máy chủ SQL

Chỉ cập nhật Năm, Tháng hoặc Ngày trong Máy chủ SQL Ngày

SQL Chuyển đổi ngày thành YYYYMMDD

Chức năng máy chủ SQL DATEDIFF

Cách lấy ngày hiện tại trong SQL Server

Sử dụng bảng lịch trong SQL Server - Phần 1

Hàm DATE trong SQL

Hiểu các múi giờ trong SQL Server

Tạo ngày ngẫu nhiên trong T-SQL

Các bài viết phổ biến

Chuyển đổi ngày và giờ bằng SQL Server

Định dạng ngày máy chủ SQL với chức năng FORMAT

SQL Server ÁP DỤNG CHÉO và ÁP DỤNG NGOÀI

SQL Server DROP TABLE IF EXISTS Các ví dụ

Ví dụ về con trỏ máy chủ SQL

Toán tử SQL NOT IN

Cuộn nhiều hàng thành một hàng và cột cho dữ liệu SQL Server

Làm cách nào để biết bạn đang chạy phiên bản SQL Server nào

SQL Chuyển đổi ngày thành YYYYMMDD

Giải quyết lỗi không thể mở kết nối với SQL Server

Cộng và trừ ngày bằng cách sử dụng DATEADD trong SQL Server

Máy chủ SQL lặp qua các hàng của bảng mà không cần con trỏ

Số lượng hàng của máy chủ SQL cho tất cả các bảng trong cơ sở dữ liệu

Sử dụng MERGE trong SQL Server để chèn, cập nhật và xóa cùng một lúc

Cách lấy ngày hiện tại trong SQL Server

Nối các cột Máy chủ SQL thành một Chuỗi với CONCAT()

Các cách so sánh và tìm sự khác biệt cho các bảng và dữ liệu SQL Server

Cơ sở dữ liệu máy chủ SQL bị kẹt trong trạng thái khôi phục

Định dạng số trong SQL Server

Thực thi các lệnh SQL động trong SQL Server




Mysql chọn mỗi ngày trong phạm vi


Mysql chọn mỗi ngày trong phạm vi




Thông tin về các Tác giả

Mysql chọn mỗi ngày trong phạm vi
Koen Verbeeck là một chuyên gia BI, chuyên về ngăn xếp BI của Microsoft với tình yêu đặc biệt dành cho SSIS.

Xem tất cả mẹo của tôi



Bài viết được cập nhật lần cuối. 2020-07-15


Nhận xét cho bài viết này

Thêm nhận xét


Chủ nhật, ngày 9 tháng 8 năm 2020 - 11. 56. 23 PM - Jeff Moden (86262)Chào Koen,

Cảm ơn bạn đã phản hồi rất tử tế. Bạn đã thực hiện một phân tích tuyệt vời trong bản cập nhật của mình cho bài viết. Tôi chắc chắn không mong đợi một bản cập nhật cho bài viết dựa trên những gì tôi đã đăng và tôi cảm ơn bạn một lần nữa vì đã dành thời gian để giúp đỡ người khác. Bạn không chỉ là một người hiểu biết về SQL Server mà còn là một chuyên gia thực sự. Tất nhiên, sau nhiều năm "biết" bạn, tôi đã biết cả hai điều đó.

Rất vui được "gặp lại" bạn và một lần nữa, cảm ơn bạn vì những gì bạn đã làm cho cộng đồng phi thường này.
Thứ Tư, ngày 29 tháng 7 năm 2020 - 3. 30. 20:00 - Koen Verbeeck (86212)

Chào Jeff,

đã lâu không gặp. )
Cảm ơn ý kiến ​​đóng góp quý báu của bạn. Tôi rất vui vì bạn đã dành thời gian để đọc bài viết của tôi và viết phản hồi toàn diện như vậy.
Thành thật mà nói, tôi chưa từng thấy thủ thuật ÁP DỤNG CHÉO trước đây, vì vậy tôi rất vui khi biết được điều gì đó mới. Tôi đã lấy bản sao cuốn sách của Itzik về Chức năng cửa sổ và anh ấy sử dụng mệnh đề TOP trong phần về bảng kiểm đếm, nhưng không kết hợp với ÁP DỤNG CHÉO.

Dù sao, truy vấn của bạn chạy nhanh hơn. Thật kỳ lạ là khi bạn chạy truy vấn của tôi và truy vấn của bạn trong cùng một đợt, kế hoạch thực thi thực tế sẽ cho biết truy vấn của tôi chiếm khoảng 7% chi phí của tổng số đợt, trong khi của bạn là 93%. Lạ lùng

Tôi đã gửi bản cập nhật cho các biên tập viên để đưa truy vấn của bạn vào bài viết cùng với một chút giải thích về cách hoạt động của truy vấn đó. Để biết chi tiết thực tế về hiệu suất, tôi tham khảo nhận xét của bạn tại đây. Mẹo sẽ được cập nhật sớm.

Một lần nữa, cảm ơn bạn đã đóng góp ý kiến ​​và quan tâm.
Koen


Thứ tư, ngày 15 tháng 7 năm 2020 - 5. 43. 24h - Jeff Moden (86140)

Tôi không thể biết câu trả lời này đã được gửi trước đó chưa và vì vậy tôi đang gửi lại. Nếu nó là một bản sao của lần gửi trước đây của tôi, xin vui lòng bỏ qua nó

Đầu tiên, tôi phải nói rằng tôi rất cảm kích bất kỳ ai đã dành thời gian viết một bài báo để chia sẻ kiến ​​thức và vì vậy cảm ơn bạn rất nhiều vì điều đó, Koen

Đề xuất của bạn về việc sử dụng Itzik Ben-Gans cCTEs (Không nên nhầm lẫn CTE xếp tầng với rCTE hoặc CTE đệ quy) nhưng có một số vấn đề về triển khai trong ví dụ cuối cùng của bạn. Trước tiên hãy xem những vấn đề là gì

Nếu chúng tôi bọc mã của bạn trong SET STATISTICS nhưng cũng bao gồm IO, chúng tôi sẽ nhận được gợi ý về sự cố đầu tiên

--===== Nếu bảng thử nghiệm đã tồn tại, hãy bỏ bảng đó để làm cho việc chạy lại trong SSMS dễ dàng hơn.
   
DROP BẢNG IF EXISTS #Test
;
--===== Run the test code measuring time AND IO
    
SET STATISTICS TIME,IO ON --Added this.
;
VỚI 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 (SELECT NULL)) FROM E32)
    
,DateRange AS
(
    
SELECT ExplodedDate = DATEADD(DAY,- 1,'2010-01-01')
    
FROM cteTally
    
WHERE N <= 5000
) --LOOK at the execution plan and see the "Eager Spool" that internally creates 226,159,403 rows!
CHỌN f. Số đơn đặt hàng, f. Số đơn hàng bán hàng, f. Ngày đặt hàng, f. Ngày đến hạn, d. Ngày bùng nổ
VÀO #Thử nghiệm
TỪ AdventureWorksDW2017.dbo. FactInternetSales f
THAM GIA DateRange d BẬT d.ExplodedDate >= f. Ngày đặt hàng
 
 d. ExplodedDate <= f. Ngày đến hạn
;
    
ĐẶT STATISTICS TIME,IO OFF --Added this
;
Here are the results from that run...

Bảng 'Bàn làm việc'. Số lần quét 5000, số lần đọc logic 1543429, số lần đọc vật lý {0, số lần đọc đọc trước {0, số lượt đọc lô-gic 0, số lượt đọc vật lý tác giả 0, số lần đọc lob phía trước đọc 0.
Bảng 'FactInternetSales'. Số lần quét 1, số lần đọc logic 1249, số lần đọc vật lý 0, số lần đọc đọc trước 0, số lượt đọc lô-gic 0, số lần đọc vật lý đọc 0, số lần đọc lob trước đọc 0.

 Thời gian thực thi máy chủ SQL.
   Thời gian CPU = 34359 ms,  thời gian đã qua = 34368 ms.

(785174 hàng bị ảnh hưởng)

Nếu bạn nhìn vào kế hoạch thực hiện, bạn sẽ phát hiện ra rằng "Worktable" là từ "Eager Spool" trong TempDB. Nó tạo ra số lượng hàng "thực tế" hơn 226 triệu hàng mà bạn đã dự đoán, nhưng chúng tôi thực sự không cần cụ thể hóa những hàng đó. Ngoài ra, nếu chúng ta chia 1543429 số lần đọc logic cho 128 để chuyển thành MegaBytes đọc, chúng tôi thấy rằng hơn 12.058 MegaByte (hơn 12 GigaByte) phải được . Bộ nhớ nhanh như vậy, đó là rất nhiều bộ nhớ không cần thiết IO.

Các vấn đề khác bao gồm thực tế là phương pháp của bạn yêu cầu kiến ​​thức bí truyền trước đó về ngày thấp nhất trong bảng có thể là ngày nào và thực tế là bạn đã bao gồm một giới hạn. 5000 ngày chỉ khoảng 13. 68 năm và có rất nhiều khoảng thời gian sẽ dễ dàng vượt xa điều đó. Vấn đề lớn với cả hai là bạn không nhất thiết phải biết khoảng thời gian ngày sẽ là bao nhiêu cũng như ngày bắt đầu thấp nhất là bao nhiêu

Chúng tôi có thể giải quyết tất cả những điều đó. Điều quan trọng là không cụ thể hóa 5000 hàng cho cteTally. Trong phần sau, tôi cũng sử dụng phiên bản "Cơ sở 16" của mã "Cơ sở 2" tốt của Itzik chỉ để làm cho mã ngắn hơn và dễ nhớ hơn rất nhiều. Tuy nhiên, đó KHÔNG phải là tốc độ đến từ đâu. Tốc độ đến từ việc sử dụng TOP trong ÁP DỤNG CHÉO, đây là phương pháp hàm ý ưa thích cho các cCTE của Itzik (như bạn sẽ thấy ngay khi chạy đoạn mã sau)

--===== Nếu bảng kiểm tra đã tồn tại, hãy bỏ nó để chạy lại trong SSMS dễ dàng hơn.
  
XẢ BẢNG NẾU TỒN TẠI< . #Test
;
--===== Run the test code measuring time AND IO
    
SET STATISTICS TIME,IO ON
;
       
WITH
       H1
(N) AS (SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))H0(N))
,cteTALLY(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM H1 a, H1 b, H1 c, H1 d, H1 e, H1 f, H1 g, H1 h)
 
SELECT f.Số đơn đặt hàng, f. Số đơn hàng bán hàng, f. Ngày đặt hàng, f. Ngày đến hạn
        
,Ngày bùng nổ =< .  DATEADD(dd,t.N-1,f . .Ngày đặt hàng)
   
VÀO #Test .
   
FROM AdventureWorksDW2017.dbo. FactInternetSales f
  
CHÉP ÁP DỤNG< .  (SELECT TOP (DATEDIFF(dd,f.Ngày đặt hàng,f. Ngày đến hạn)+1) . Vâng. nó thực sự đã chạy. . DFROM cteTally ORDER BY N) t
;
    
SET STATISTICS TIME,IO OFF;

Here are the results from that run.. yes.. it actually did run. :D
Bảng 'FactInternetSales'. Số lần quét 9, số lần đọc logic 1315, số lần đọc vật lý 0, số lần đọc trước 0, số lần đọc logic 0, số lần đọc vật lý 0, số lần đọc trước 0.

  Thời gian thực thi máy chủ SQL.
   Thời gian CPU = 452 mili giây,   thời gian đã trôi qua = 82 mili giây.

(785174 hàng bị ảnh hưởng)

Nếu bạn muốn tiến thêm một bước, hãy tạo một iTVF (Hàm có giá trị trong bảng nội tuyến) và mã của bạn sẽ trông đơn giản như sau

Làm cách nào để lấy dữ liệu một ngày trong MySQL?

Khoảng thời gian 1 ngày là gì?

Và INTERVAL hoạt động như được đặt tên, e. g. THỜI GIAN 1 NGÀY = 24 giờ .

Làm cách nào để có được tất cả các ngày giữa phạm vi ngày trong truy vấn SQL?

Để tìm sự khác biệt giữa các ngày, hãy sử dụng hàm DATEDIFF(datepart, startdate, enddate) . Đối số datepart xác định phần ngày/thời gian mà bạn muốn thể hiện sự khác biệt. Giá trị của nó có thể là năm, quý, tháng, ngày, phút, v.v.

Làm cách nào để thêm 15 ngày vào ngày hiện tại trong MySQL?

Sử dụng hàm DATE_ADD() nếu bạn muốn tăng một ngày nhất định trong cơ sở dữ liệu MySQL.