2009-03-04 4 views
4

Ich arbeite an einer Website mit einer einfachen normalisierten Datenbank.Sollten die Summen demormalisiert werden?

Es gibt eine Tabelle namens Pages und eine Tabelle namens Views. Jedes Mal, wenn eine Seite angezeigt wird, wird ein eindeutiger Datensatz dieser Ansicht in der Tabelle "Ansichten" aufgezeichnet.

Beim Anzeigen einer Seite auf der Website verwende ich eine einfache MySQL COUNT(), um die Anzahl der Ansichten für die Anzeige zusammenzufassen.

Datenbank-Design scheint gut, außer für dieses Problem: Ich bin ratlos, wie die Top 10 der am häufigsten angesehenen Seiten unter Tausenden abgerufen werden.

Sollte ich die Pages-Tabelle denormalisieren, indem ich eine Pages.views-Spalte hinzufüge, die die Gesamtzahl der Ansichten für jede Seite enthält? Oder gibt es eine effiziente Möglichkeit, die Top 10 der am häufigsten angesehenen Seiten abzufragen?

Antwort

8
SELECT p.pageid, count(*) as viewcount FROM 
    pages p 
    inner join views v on p.pageid = v.pageid 
    group by p.pageid 
    order by count(*) desc 
    LIMIT 10 OFFSET 0; 

Ich kann das nicht testen, aber etwas in diese Richtung. Ich würde den Wert nicht speichern, es sei denn, ich habe aufgrund von Leistungseinschränkungen (ich habe gerade den Begriff "vorzeitige Optimierung" gelernt, und es scheint zu gelten, wenn Sie dies tun).

+1

+1 für die Erwähnung, die Summen nicht zu speichern, bis ein Leistungsproblem auftritt. – Thilo

1

Ich würde wahrscheinlich die Ansichten Spalte in der Pages-Tabelle enthalten.

Es scheint wie eine vollkommen angemessene Brechen der Normalisierung zu mir. Zumal ich mir nicht vorstellen kann, dass Sie Ansichten löschen, damit Sie nicht erwarten, dass die Zählung aus dem Ruder läuft. Die referenzielle Integrität scheint in diesem Fall nicht überkritisch zu sein.

1

Bei der Datenbanknormalisierung geht es um die effizienteste/am wenigsten redundante Möglichkeit zum Speichern von Daten. Dies ist gut für die Transaktionsverarbeitung, steht jedoch oft in direktem Konflikt mit der Notwendigkeit, die Daten effizient wieder zu entfernen. Das Problem wird normalerweise dadurch gelöst, dass abgeleitete Tabellen (Indizes, materialisierte Ansichten, Rollup-Tabellen ...) mit besser zugänglichen, vorverarbeiteten Daten vorliegen. Das (etwas veraltete) Stichwort ist Data Warehousing.

Ich denke, dass Sie Ihre Pages-Tabelle normalisieren möchten, aber eine zusätzliche Tabelle mit den Summen haben. Abhängig davon, wie aktuell diese Anzahl sein muss, können Sie die Tabelle aktualisieren, wenn Sie die ursprüngliche Tabelle aktualisieren, oder Sie können einen Hintergrundjob haben, um die Summen regelmäßig neu zu berechnen.

Sie möchten dies auch nur tun, wenn Sie wirklich auf ein Leistungsproblem stoßen, das Sie nicht, wenn Sie eine sehr große Anzahl von Datensätzen oder eine sehr große Anzahl von gleichzeitigen Zugriffen haben. Halten Sie Ihren Code flexibel, damit Sie zwischen der Tabelle wechseln und nicht wechseln können.

0

Denormalisierung würde in diesem Fall definitiv funktionieren. Ihr Verlust ist der zusätzliche Lagerraum, der von der zusätzlichen Spalte verbraucht wird.

Alternativ können Sie einen geplanten Job einrichten, um diese Informationen jede Nacht zu füllen, wenn der Datenverkehr gering ist, x Zeitraum.

In diesem Fall würden Sie die Fähigkeit verlieren, Ihre Seitenzahlen sofort zu kennen, wenn Sie diese Abfrage nicht manuell ausführen.

Denormalisierung kann definitiv zur Leistungssteigerung eingesetzt werden.

--Kris

+0

Der Verlust ist sowohl die zusätzliche Spalte als auch die Notwendigkeit, sie konsistent zu halten. Ich stimme zu, dass dies in diesem Fall jedoch gerechtfertigt ist. – thomasrutter

3

Es hängt von der Höhe der Informationen, die Sie zu halten versuchen. Wenn du aufzeichnen möchtest, wer wann angesehen hat? Dann ist der separate Tisch in Ordnung. Ansonsten ist eine Spalte für Views der richtige Weg.Wenn Sie eine separate Spalte beibehalten, werden Sie feststellen, dass die Tabelle häufiger gesperrt wird, da jede Seitenansicht versucht, die Spalte für die entsprechende Zeile zu aktualisieren.

Select pageid, Count(*) as countCol from Views 
group by pageid order by countCol DESC 
LIMIT 10 OFFSET 0;