2015-12-19 2 views
9

Wir optimieren derzeit eine MySQL-Tabelle (InnoDB), die mehr als 100 Millionen Zeilen haben wird.Index für Spalte mit 70% der leeren Werte: Verwenden Sie null oder leer?

In einer Spalte speichern wir IP-Adressen (VARCHAR 45). Wir müssen einen Index für diese Spalte erstellen, da wir alle Zeilen pro spezifischer IP-Adresse abrufen können.

70% aller Zeilen wird jedoch speichern keine IP-Adresse (leer).

Unsere Frage: Sollen wir diese leeren Werte als NULL speichern und somit NULL für diese Spalte zulassen (fügt jeder Zeile 1 Byte hinzu). Oder sollen wir NULL nicht zulassen und diese leeren Werte als '' (leere Zeichenfolge) speichern?

Was ist das Beste für die Leistung?

Wir werden nie Zeilen suchen müssen, die leer sind (= '') oder Null (IS NULL), nur nach bestimmten IP-Adressen (= '123.456.789.123') suchen.

Update: Es gibt tatsächlich viele Fragen zu SO, die ähnliche Szenarien behandeln. Einige Antworten scheinen jedoch widersprüchlich zu sein oder sagen "es kommt darauf an". Wir werden einige Tests durchführen und unsere Ergebnisse für unser spezifisches Szenario hier veröffentlichen.

+0

Ich könnte mir vorstellen, dass die leere Zeichenfolge etwas leistungsfähiger wäre, da sie weniger Speicherplatz benötigt. Der Index wäre im Prinzip derselbe. Die beste Lösung ist die, die Sie TESTEN und überprüfen, ist schneller – Grantly

+1

Mögliches Duplikat von [MySQL: NULL vs ""] (http://stackoverflow.com/questions/1106258/mysql-null-vs) – Shadow

+0

@Shadow Ja, scheint wie Eine ähnliche Frage - aber auf den ersten Blick scheinen mir die zwei Antworten mit der höchsten Punktzahl das Gegenteil zu sagen? Einer sagt "benutze null", der andere sagt "nimm nicht null!". –

Antwort

2

VARCHAR(39) ist ausreichend für IPv4 (das alte Format, für das keine Werte mehr verfügbar sind) und IPv6.

Der Optimierer kann Fehler machen, wenn 70% der Werte gleich sind ('' oder NULL). Ich schlage vor, Sie haben eine andere Tabelle mit der IP und eine ID für die Rückkehr zu Ihrer ursprünglichen Tabelle. Wenn keine "leeren" IPs in der zweiten Tabelle vorhanden sind, ist es wahrscheinlicher, dass der Optimierer "das Richtige tut".

Mit diesem kann LEFT JOIN verwendet werden, um zu sehen, ob es eine IP gibt.

IPv6 kann in BINARY (16) gespeichert werden, um Platz zu sparen.

+0

Wenn die zweite Tabelle keine leeren IP-Adressen hatte, müssten Sie null als Fremdschlüssel verwenden, wodurch Sie wieder dorthin gelangen, wo Sie angefangen haben. – EJP

+0

Das ist ein Argument gegen FKs. Sie sind nicht in allen Situationen nützlich. –

+1

@EJP Sie missverstanden. Rick schlägt eine has one-Beziehung vor, bei der die neue Tabelle einen Verweis auf das Original hat. In der ursprünglichen Tabelle wäre keine IP- oder IP_id-Spalte vorhanden. – Arth

0

Der Hauptunterschied zwischen NULL und einer leeren Zeichenfolge bezieht sich auf Vergleichen von Werten. Zwei leere Zeichenfolgen werden als gleich angesehen. Zwei NULL Werte sind nicht. Wenn Sie beispielsweise zwei Tabellen basierend auf IP-Wertspalten verknüpfen möchten, ist das Ergebnis für leere und leere Zeichenfolgen sehr unterschiedlich, und höchstwahrscheinlich möchten Sie das Verhalten von NULL.

Wenn Sie nur nach bestimmten IP-Adressen suchen, spielt die Verwendung von NULL oder eine leere Zeichenfolge keine Rolle. Wenn die IP-Wert-Spalte indiziert ist, erhält der Optimierer von InnoDB eine Schätzung der Anzahl der Zeilen mit dem spezifischen Wert . Die allgemeine Statistik über die Anzahl der Zeilen pro Wert wird in diesem Fall nicht verwendet.

Durch die Vermeidung von NULL-Werten sparen Sie 30 MB bei 100 Millionen Zeilen, wenn 70% der Zeilen NULL sind. (Für Zeilen, deren Wert eine leere Zeichenfolge ist, werden Sie keinen Speicherplatz speichern, da Sie stattdessen ein Byte benötigen, um die Längeninformationen zu speichern.) Im Vergleich zu dem, was Sie speichern können, indem Sie IP-Werte als Binär-String speichern, ist dies nichts, und ich denke nicht, Storage Overhead ist ein gültiges Anliegen.

+0

Die Raumkosten von 'NULL'-Werten sind nur in MyISAM relevant. InnoDB hat keine Platzkosten für 'NULL'. – manchicken

+0

InnoDB-Zeilenköpfe enthalten einen Bitvektor über Spalten, die NULL sind. Wenn keine NULL-Spalten vorhanden sind, enthält der Zeilenkopf diesen Bitvektor nicht. Daher wird eine Tabelle ohne NULL-Spalten 1 Byte weniger pro Zeile als die gleiche Tabelle mit 1-8 NULL-Spalten verwenden. Siehe https://dev.mysql.com/doc/refman/5.7/en/innodb-physical-record.html – oysteing

1

Gehen Sie mit NULL Werte. InnoDB hat keine Platzkosten für NULL s und NULL Werte sind von Indizes ausgeschlossen, so dass Sie eine schnellere Indexsuche für die vorhandenen Werte haben.

Soweit, wie Sie die IP selbst speichern (String Verus-Nummer), scheint das ein weit weniger wichtiger Punkt der Optimierung.

Verwandte Themen