Twoje dane są źle zgrupowane .
InnoDB będzie przechowywać wiersze z „zamkniętymi” plikami PK fizycznie blisko siebie. Ponieważ Twoje tabele podrzędne używają zastępczych PK, ich wiersze będą przechowywane losowo. Kiedy nadejdzie czas na wykonanie obliczeń dla danego wiersza w tabeli „głównej”, DBMS musi przeskoczyć w różne miejsca, aby zebrać powiązane wiersze z tabel podrzędnych.
Zamiast kluczy zastępczych, spróbuj użyć bardziej „naturalnych” kluczy, z PK rodzica na krawędzi natarcia, podobnie do tego:
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)
UWAGA:Zakłada się, że created
rozdzielczość jest wystarczająco dobra, a rating_no
został dodany, aby umożliwić wiele ocen na entry_id
. To tylko przykład — możesz zmieniać PK zgodnie ze swoimi potrzebami.
To „wymusi” wiersze należące do tego samego entry_id
być fizycznie przechowywane blisko siebie, więc sumę lub AVG można obliczyć po prostu przez skanowanie zakresu za pomocą klucza PK/klastrowania i przy bardzo małej liczbie operacji we/wy.
Alternatywnie (np. jeśli używasz MyISAM, który nie obsługuje klastrowania), okładka zapytanie z indeksami, więc tabele podrzędne nie są w ogóle dotykane podczas wykonywania zapytania.
Ponadto możesz zdenormalizować swój projekt i buforować bieżące wyniki w tabeli nadrzędnej:
- Przechowuj SUM(score_adjustments.amount) jako pole fizyczne i dostosowuj je za pomocą wyzwalaczy za każdym razem, gdy wiersz jest wstawiany, aktualizowany lub usuwany z
score_adjustments
. - Przechowuj SUM(rating_adjustments.rating) jako „S” i COUNT(rating_adjustments.rating) jako „C”. Gdy wiersz zostanie dodany do
rating_adjustments
, dodaj go do S i zwiększ C. Oblicz S/C w czasie wykonywania, aby uzyskać średnią. Podobnie postępuj z aktualizacjami i usuwaniem.