2010-07-31 53 views

Trả lời

5

Nó có vẻ như tôi đang đưa ra lời khuyên này ba lần một tuần ở đây trên SO, có lẽ tôi chỉ nên từ bỏ và để cho nó đi :-) Nah, tôi không nghĩ như vậy:

Don' t chức năng sử dụng cho mỗi hàng trong tính toán cột của bạn (hoặc order by khoản) nếu bạn muốn cơ sở dữ liệu của bạn để mở rộng quy mô tốt. Bạn nên kiểm tra hiệu suất cho trường hợp của bạn đặc biệt (biện pháp, không đoán) nhưng làm phép tính khi đọc cơ sở dữ liệu nói chung sẽ ảnh hưởng đến khả năng của bạn để mở rộng (điều này sẽ không thành vấn đề đối với cơ sở dữ liệu sổ địa chỉ của bạn, nhưng các cửa hàng tôi làm việc có số lượng lớn lượng dữ liệu).

Số lượng "làm thế nào để tôi nhận được DB của tôi để đi nhanh hơn?" câu hỏi vượt xa số lượng "làm thế nào để tôi sử dụng ít không gian hơn?" những người. Đó là một con đường tốt để hy sinh không gian đĩa cho hiệu suất.

Các thời điểm thích hợp để làm các phép tính là khi thay đổi dữ liệu. Bằng cách đó, chi phí của các thay đổi được phân bổ trên tất cả các lần đọc.

Lời khuyên của tôi là tạo ra một cột như dtLastAction để chứa các giá trị đặt hàng sau đó sử dụng một chèn/cập nhật kích hoạt để đặt nó là giống như dtModified nếu không null, hoặc dtPosted nếu dtModified là null. Về mặt kỹ thuật, điều này vi phạm 3NF nhưng không sao nếu bạn biết bạn đang làm gì và các trình kích hoạt đảm bảo tính nhất quán của dữ liệu trong trường hợp đó.

Sau đó, chỉ mục trên cột dtLastAction và xem tốc độ truy vấn của bạn được cải thiện với chi phí (ít hơn) của một số công việc phụ trong khi chèn và cập nhật. Tôi nói ít hơn bởi vì hầu hết các bảng cơ sở dữ liệu được đọc nhiều hơn so với văn bản (rõ ràng phương pháp này là vô dụng nếu tình huống cụ thể của bạn là một trong những trường hợp ngoại lệ rất hiếm).

Ngoài ra, đối với trường hợp đặc biệt này, bạn có thể thiết dtModifieddtPosted với giá trị tương tự khi tạo các mục nhập, có nghĩa là sẽ không bao giờ dtModifiedđược null. Bạn vẫn có thể phát hiện các bài đăng chưa bao giờ được sửa đổi bởi thực tế là hai giá trị datetime này giống hệt nhau.

+0

vâng, tôi nghĩ' dtLastAction' là rất tốt. có thể kiểm tra nếu kiểm tra nếu 'dtModified' giống với' dtPosted' thậm chí còn lớn hơn. tôi không cần thêm 1 trường nữa. có thể đổi tên 'dtModified' thành' dtLastAction' sẽ làm cho nó trực quan hơn –

+0

Nói chung tôi đồng ý với việc giảm chi phí đọc. Tuy nhiên, trường hợp cụ thể này rất đơn giản, tôi không nghĩ nó biện minh cho tất cả sự phức tạp của bộ nhớ đệm. Ví dụ. nếu hành động bị xóa thì bạn cần cập nhật ngày hành động cuối cùng cho hành động mới nhất còn lại, cơn ác mộng! – malhal

13

Bạn có thể sử dụng COALESCE:

ORDER BY COALESCE(dtModified, dtPosted) 

Một lựa chọn khác là sử dụng các chức năng cụ thể MySQL IFNULL thay vì COALESCE.


kiểm tra trên MySQL:

CREATE TABLE table1 (dtModified DATETIME NULL, dtPosted DATETIME NOT NULL); 
INSERT INTO table1 (dtModified, dtPosted) VALUES 
('2010-07-31 10:00:00', '2010-07-30 10:00:00'), 
(NULL     , '2010-07-31 09:00:00'), 
('2010-07-31 08:00:00', '2010-07-30 10:00:00'); 

SELECT dtModified, dtPosted 
FROM table1 
ORDER BY COALESCE(dtModified, dtPosted) 

Kết quả:

dtModified   dtPosted 
2010-07-31 08:00:00 2010-07-30 10:00:00 
NULL     2010-07-31 09:00:00 
2010-07-31 10:00:00 2010-07-30 10:00:00 
+0

bạn có thể sử dụng COALESCE trong ORDER BY không? –

+0

Có, tôi nghĩ bạn phải sử dụng 'IFNULL' cho MySQL. –

+0

@Daniel Vassallo: Tôi vừa thử nghiệm nó trong MySQL và nó có vẻ hoạt động tốt. Xem câu trả lời cập nhật của tôi cho SQL tôi đã sử dụng. –

0

Trong SELECT của bạn, sử dụng một lệnh CASE mà mất giá trị của ngày sửa đổi nếu không phải là null nếu không thì thời gian đăng tuyển. Sau đó, sử dụng cột "được tính toán" mới cho ORDER BY của bạn.

Các vấn đề liên quan