2011-01-05 18 views
0

Ich fragte eine ähnliche Frage vor (integer-vs-char-for-db-record-property) aber stolperte über etwas, das gegen alle Empfehlungen, die ich in meinem früheren Post erhalten hatte, widerspricht. In Wordpress 3, dem populärsten und ausgereiftesten Open-Source-Blog-Skript, wird der Post-Status als VARCHAR(20) in db gespeichert - 'publish', 'auto-draft', 'inherit', 'pending' usw. und nicht als INT mit Nachschlagetabelle oder gemappte String-Konstanten, oder CHAR, oder etwas ähnliches. Dies gilt auch für das Feld post_type ('post', 'attachment', 'revision' usw.) und einige andere Felder. Um also alle veröffentlichten Posts zu finden, muss ich etwas wie SELECT * FROM posts WHERE post_status = 'published' AND post_type = 'post' ausführen. Außerdem gibt es einen mehrspaltigen Index für post_status, post_type und einige andere Spalten, der diese Art der Suche sicherlich beschleunigt. Kann jemand erklären, warum sie es so und nicht anders gemacht haben, und welche Vor- und Nachteile hat dieser Ansatz?Integer vs Char für DB-Record-Eigenschaft vs Wordpress-Schema

Antwort

1

Nur weil eine Anwendung bekannt ist, bedeutet das nicht, dass sie ein gutes Datenbankdesign haben. Dies tendiert dazu, die Normalisierungsregeln zu verletzen. Vielleicht bekommen sie bessere Leistungen und vielleicht haben sie sich die anderen Möglichkeiten nicht angesehen, als sie sich für diese entschieden haben, weil sie es nicht besser wussten. Vielleicht waren sie Anwendungsprogrammierer, die eine Datenbank entwarfen, ohne die Datenbanktheorie sehr gut zu verstehen, oder vielleicht war es eine bewusste Denormierung mit Leistungsstatistiken, um das zu untermauern. Oder sie dachten nicht an die Möglichkeit, 100 Millionen Datensätze auf den neuesten Stand zu bringen, als wir beschlossen, den Wert von "veröffentlicht" in etwas anderes zu ändern. Vielleicht haben sie nur die Leistung von Selects getestet, aber nicht von Updates. Vielleicht ändern sich die Werte im Allgemeinen unweigerlich, also ist es keine so große Sache zu denormalisieren. Wir können es von hier nicht wissen.

+2

Speichern von Status und post_type als Strings kann möglicherweise nicht "die Normalisierungsregeln verletzen" (oder sogar "tendieren", sie zu verletzen, soweit ich sehen kann). Das Design, das Vincent beschrieben hat, könnte die Datenbank möglicherweise viel größer machen, als es sein müsste, aber das ist eine andere Frage. Die Normalisierung ist völlig unabhängig von der Art der in einer Spalte gespeicherten Daten und hat nichts mit der Speichergröße zu tun. Ich denke, das sollte klar sein. – sqlvogel

1

Bei der Normalisierung geht es nicht darum, Strings durch Zahlen zu ersetzen oder Strings zu "teilen", nur weil sie die gleichen Buchstaben haben.

Ich kenne ihr Design nicht, aber das folgende Szenario ist perfekt normalisiert, obwohl es Zeichenfolgen als Bezeichner verwendet.

create table post_statuses(
    status varchar(20) not null 
    ,primary key(status) 
); 

insert into post_statuses values('publish'); 
insert into post_statuses values('inherit'); 
insert into post_statuses values('pending'); 

create table posts(
    post_id ... 
    status varchar(20) not null 
    ,primary key(post_id) 
    ,foreign key(status) references post_statuses(status) 
); 

Der Hauptvorteil von natürlichen Schlüsseln über Ersatzschlüssel ist, dass es die Anzahl der Joins benötigt und auch die Wahrscheinlichkeit, dass ganze Klassen von Anfragen aus dem Index reduziert nur beantwortet werden können. Die Hauptnachteile sind erhöhte Speicherkapazität und die Möglichkeit, eine Hölle zu haben, wenn wir die Werte ändern müssen.

0

Ich würde vermuten, dass die WP-Entwickler einfach vermieden haben, was sie als vorzeitige Optimierung empfanden, und entschieden sich stattdessen für eine bessere Lesbarkeit.

"SELECT * FROM posts WHERE post_status = 'published' AND post_type = 'post'" 

ist ein wenig etwas leichter als

"SELECT * FROM posts WHERE post_status = ".WP_POST_STATUS_PUBLISHED." 
    AND post_type = ".WP_POST_TYPE_POST."" 

zu lesen und wenn ein neuer WP Entwickler eine select * from ... Abfrage ausgeführt wird, ‚veröffentlicht‘ die Datenbanktabelle Listen anstatt 3 oder 5, das ist einfacher zu verstehen und zu debuggen.

Aus der Sicht des Plattenspeicherplatzes, ist entweder Ansatz ziemlich okay, denke ich - einige mehr post_status Bytes sollte nicht viel im Vergleich zu dem Blog-Post Text und alle anderen Spalten. Ein Integer ist 8 Bytes (gut, es sei denn, es ist ein Tinyint) und "veröffentlicht" ist vielleicht 10 Bytes, also spielt es keine Rolle?