Đây là một mô hình để đạt được yêu cầu đã nêu của bạn.
Liên kết đến Mô hình Dữ liệu Chuỗi thời gian
Liên kết tới IDEF1X Notation dành cho những người không quen với Tiêu chuẩn mô hình quan hệ.
-
Chuẩn hóa thành 5NF; không có cột trùng lặp; không có bất thường cập nhật, không có giá trị.
-
Khi Trạng thái của Sản phẩm thay đổi, chỉ cần chèn một hàng vào ProductStatus, với DateTime hiện tại. Không cần phải chạm vào các hàng trước đó (đúng và vẫn đúng). Không có giá trị giả nào mà các công cụ báo cáo (ngoài ứng dụng của bạn) phải diễn giải.
-
DateTime là DateTime thực tế mà Sản phẩm được đặt ở Trạng thái đó; "Từ", nếu bạn muốn. "Đến" có thể dễ dàng bắt nguồn:nó là DateTime của hàng tiếp theo (DateTime> "From") cho Sản phẩm; nếu nó không tồn tại, giá trị là DateTime hiện tại (sử dụng ISNULL).
Mô hình đầu tiên đã hoàn thành; (ProductId, DateTime) là đủ để cung cấp tính duy nhất cho Khóa chính. Tuy nhiên, vì bạn yêu cầu tốc độ cho các điều kiện truy vấn nhất định, chúng tôi có thể nâng cao mô hình ở cấp độ vật lý và cung cấp:
-
Chỉ mục (chúng tôi đã có Chỉ mục PK, vì vậy chúng tôi sẽ cải thiện chỉ mục đó trước tiên, trước khi thêm chỉ mục thứ hai) để hỗ trợ các truy vấn được đề cập (những truy vấn dựa trên bất kỳ sự sắp xếp nào của {ProductId | DateTime | Status} có thể được Chỉ mục cung cấp mà không cần để chuyển đến các hàng dữ liệu). Điều này làm thay đổi quan hệ Trạng thái ::Tình trạng sản phẩm từ Không nhận dạng (đường đứt đoạn) thành Loại nhận dạng (đường liền nét).
-
Sắp xếp PK được chọn trên cơ sở hầu hết các truy vấn sẽ là Chuỗi thời gian, dựa trên Sản phẩm⇢DateTime⇢Status.
-
Chỉ mục thứ hai được cung cấp để nâng cao tốc độ truy vấn dựa trên Trạng thái.
-
Trong Bố trí Thay thế, điều đó được đảo ngược; tức là, chúng tôi chủ yếu muốn trạng thái hiện tại của tất cả các Sản phẩm.
-
Trong tất cả các phiên bản của ProductStatus, cột DateTime trong Chỉ mục phụ (không phải PK) là DESCending; gần đây nhất là đầu tiên.
Tôi đã cung cấp cuộc thảo luận mà bạn yêu cầu. Tất nhiên, bạn cần thử nghiệm với tập dữ liệu có kích thước hợp lý và đưa ra quyết định của riêng mình. Nếu có gì chưa hiểu ở đây các bạn cứ hỏi, mình sẽ mở rộng thêm.
Phản hồi nhận xét
Báo cáo tất cả các Sản phẩm có Trạng thái Hiện tại là 2
SELECT ProductId,
Description
FROM Product p,
ProductStatus ps
WHERE p.ProductId = ps.ProductId -- Join
AND StatusCode = 2 -- Request
AND DateTime = ( -- Current Status on the left ...
SELECT MAX(DateTime) -- Current Status row for outer Product
FROM ProductStatus ps_inner
WHERE p.ProductId = ps_inner.ProductId
)
-
ProductId
được lập chỉ mục, col dẫn đầu, cả hai bên -
DateTime
trong Đã lập chỉ mục, cột thứ 2 trong Tùy chọn truy vấn được bao phủ -
StatusCode
được lập chỉ mục, cột thứ 3 trong Tùy chọn truy vấn được bao phủ -
Kể từ
StatusCode
trong Chỉ mục là DESCending, chỉ cần một lần tìm nạp để đáp ứng truy vấn bên trong -
các hàng được yêu cầu cùng một lúc, cho một truy vấn; chúng gần nhau (do Clstered Index); hầu như luôn ở trên cùng một trang do kích thước hàng ngắn.
Đây là SQL thông thường, một truy vấn con, sử dụng sức mạnh của công cụ SQL, xử lý tập hợp quan hệ. Đây là một phương pháp đúng , không có gì nhanh hơn và bất kỳ phương pháp nào khác sẽ chậm hơn. Bất kỳ công cụ báo cáo nào cũng sẽ tạo ra mã này với một vài cú nhấp chuột, không cần nhập.
Hai ngày trong trạng thái sản phẩm
Các cột như DateTimeFrom và DateTimeTo là các lỗi tổng thể. Hãy xem nó theo thứ tự quan trọng.
-
Đó là một lỗi Chuẩn hóa tổng thể. "DateTimeTo" có thể dễ dàng bắt nguồn từ DateTime duy nhất của hàng tiếp theo; do đó, nó là thừa, một cột trùng lặp.
- Không đạt được độ chính xác:điều đó có thể dễ dàng giải quyết nhờ DataType (DATE, DATETIME, SMALLDATETIME). Cho dù bạn hiển thị dưới một giây, micro giây hay nano giây, là một quyết định kinh doanh; nó không liên quan gì đến dữ liệu được lưu trữ.
-
Việc triển khai cột DateTo là bản sao 100% (của DateTime của hàng tiếp theo). Điều này chiếm gấp đôi dung lượng ổ đĩa . Đối với một chiếc bàn lớn, đó sẽ là một sự lãng phí đáng kể không cần thiết.
-
Do đó là một hàng ngắn, bạn sẽ cần gấp đôi số lượng I / Os vật lý và logic để đọc bảng trên mọi lần truy cập.
-
Và gấp đôi dung lượng bộ nhớ cache (hoặc nói một cách khác, chỉ một nửa số hàng sẽ phù hợp với bất kỳ không gian bộ nhớ cache nhất định nào).
-
Bằng cách giới thiệu một cột trùng lặp, bạn đã đưa ra khả năng xảy ra lỗi (giá trị hiện có thể được lấy theo hai cách:từ cột DateTimeTo trùng lặp hoặc DateTimeFrom của hàng tiếp theo).
-
Đây cũng là một Điểm bất thường về cập nhật . Khi bạn cập nhật bất kỳ DateTimeFrom nào được cập nhật, DateTimeTo của hàng trước đó phải được tìm nạp (không có vấn đề gì lớn vì nó đã gần xong) và Cập nhật (vấn đề lớn vì nó là một động từ bổ sung có thể tránh được).
-
"Ngắn hơn" và "phím tắt mã hóa" không liên quan, SQL là một ngôn ngữ thao tác dữ liệu cồng kềnh, nhưng SQL là tất cả những gì chúng ta có (Chỉ cần đối phó với nó). Bất kỳ ai không thể mã hóa một truy vấn con thực sự không nên mã hóa. Bất kỳ ai sao chép một cột để giảm bớt "khó khăn" mã hóa nhỏ thực sự không nên mô hình hóa cơ sở dữ liệu.
Xin lưu ý rằng nếu quy tắc bậc cao nhất (Chuẩn hóa) được duy trì, thì toàn bộ tập hợp các vấn đề bậc thấp hơn sẽ bị loại bỏ.
Suy nghĩ trong Điều khoản của Bộ
-
Bất kỳ ai gặp "khó khăn" hoặc gặp "đau đớn" khi viết SQL đơn giản đều bị tê liệt trong việc thực hiện chức năng công việc của họ. Thông thường, nhà phát triển không suy nghĩ về bộ và Cơ sở dữ liệu quan hệ là mô hình hướng tập hợp .
-
Đối với truy vấn ở trên, chúng ta cần DateTime hiện tại; vì ProductStatus là một bộ của Trạng thái Sản phẩm theo thứ tự thời gian, chúng tôi chỉ cần mới nhất hoặc MAX (DateTime) của bộ thuộc về Sản phẩm.
-
Bây giờ chúng ta hãy xem xét một cái gì đó được cho là "khó", xét về bộ . Đối với báo cáo về khoảng thời gian mà mỗi Sản phẩm đã ở trong một Trạng thái cụ thể:DateTimeFrom là một cột có sẵn và xác định giới hạn theo chiều ngang, một bộ phụ (chúng ta có thể loại trừ các hàng trước đó); DateTimeTo là phiên bản sớm nhất của bộ phụ của Quốc gia Sản phẩm.
SELECT ProductId,
Description,
[DateFrom] = DateTime,
[DateTo] = (
SELECT MIN(DateTime) -- earliest in subset
FROM ProductStatus ps_inner
WHERE p.ProductId = ps_inner.ProductId -- our Product
AND ps_inner.DateTime > ps.DateTime -- defines subset, cutoff
)
FROM Product p,
ProductStatus ps
WHERE p.ProductId = ps.ProductId
AND StatusCode = 2 -- Request
-
Suy nghĩ về cách nhận hàng tiếp theo được định hướng theo hàng, không phải xử lý theo định hướng. Khủng hoảng, khi làm việc với cơ sở dữ liệu hướng tập hợp. Hãy để Người tối ưu làm tất cả những điều đó cho bạn. Kiểm tra SHOWPLAN của bạn, điều này tối ưu hóa rất tốt.
-
Không có khả năng suy nghĩ trong bộ , do đó bị giới hạn trong việc chỉ viết các truy vấn mức đơn, không phải là lý do hợp lý cho việc:thực hiện trùng lặp lớn và Cập nhật Bất thường trong cơ sở dữ liệu; lãng phí tài nguyên trực tuyến và không gian đĩa; đảm bảo một nửa hiệu suất. Rẻ hơn nhiều khi học cách viết các truy vấn con SQL đơn giản để lấy dữ liệu dễ dàng dẫn xuất.