Dữ liệu của bạn bị kém nhóm .
InnoDB sẽ lưu trữ các hàng có PK "gần" nhau về mặt vật lý. Vì bảng con của bạn sử dụng PK thay thế, các hàng của chúng sẽ được lưu trữ có hiệu lực một cách ngẫu nhiên. Khi đến thời điểm thực hiện các phép tính cho hàng nhất định trong bảng "chính", DBMS phải nhảy khắp nơi để thu thập các hàng liên quan từ các bảng con.
Thay vì các khóa thay thế, hãy thử sử dụng các khóa "tự nhiên" hơn, với PK gốc ở cạnh trước, tương tự như sau:
score_adjustments:
entry_id: INT(11), FOREIGN KEY (entries.id)
created: DATETIME
amount: INT(4)
PRIMARY KEY (entry_id, created)
rating_adjustments:
entry_id: INT(11), FOREIGN KEY (entries.id)
rating_no: INT(11)
rating: DOUBLE
PRIMARY KEY (entry_id, rating_no)
LƯU Ý:Điều này giả sử created
Độ phân giải của đủ tốt và rating_no
đã được thêm vào để cho phép nhiều xếp hạng trên mỗi entry_id
. Đây chỉ là một ví dụ - bạn có thể thay đổi PK tùy theo nhu cầu của mình.
Điều này sẽ "buộc" các hàng thuộc cùng một entry_id
được lưu trữ gần nhau về mặt vật lý, do đó, SUM hoặc AVG có thể được tính toán chỉ bằng cách quét phạm vi trên khóa PK / phân cụm và với rất ít I / Os.
Ngoài ra (ví dụ:nếu bạn đang sử dụng MyISAM không hỗ trợ phân cụm), bìa truy vấn với các chỉ mục để các bảng con không bị chạm vào trong quá trình truy vấn.
Trên hết, bạn có thể chuẩn hóa thiết kế của mình và lưu vào bộ nhớ cache các kết quả hiện tại trong bảng chính:
- Lưu trữ SUM (score_adjustments.amount) dưới dạng trường vật lý và điều chỉnh nó thông qua trình kích hoạt mỗi khi một hàng được chèn, cập nhật hoặc xóa khỏi
score_adjustments
. - Lưu trữ SUM (rating_adjustments.rating) là "S" và COUNT (rating_adjustments.rating) là "C". Khi một hàng được thêm vào
rating_adjustments
, thêm nó vào S và tăng dần C. Tính S / C tại thời điểm chạy để lấy giá trị trung bình. Xử lý cập nhật và xóa tương tự.