Soll ich die Zeit investieren, um den Spaltentyp von CHAR (36) auf UUID zu ändern?

14

Ich habe bereits einige Millionen Zeilen in meiner Datenbank. Ich wusste nichts über den PostgreSQL-UUID-Datentyp, als ich mein Schema entwarf.

Eine der Tabellen verfügt über 16 Millionen Zeilen (ca. 3,5 bis 4 Millionen Datensätze pro Shard) und wächst mit ca. 500.000 Datensätzen pro Tag. Ich habe immer noch den Luxus, das Produktionssystem bei Bedarf für ein paar Stunden herunterzufahren. Ich werde diesen Luxus in ein oder zwei Wochen nicht haben.

Meine Frage ist, lohnt sich das? Ich wundere mich über die JOIN-Leistung, die Speicherplatznutzung (vollständiger gzip-Dump ist 1,25 GiB) und solche Dinge.

Das Tabellenschema ist:

# \d twitter_interactions
                Table "public.twitter_interactions"
         Column          |            Type             | Modifiers 
-------------------------+-----------------------------+-----------
 interaction_id          | character(36)               | not null
 status_text             | character varying(1024)     | not null
 screen_name             | character varying(40)       | not null
 twitter_user_id         | bigint                      | 
 replying_to_screen_name | character varying(40)       | 
 source                  | character varying(240)      | not null
 tweet_id                | bigint                      | not null
 created_at              | timestamp without time zone | not null
Indexes:
    "twitter_interactions_pkey" PRIMARY KEY, btree (interaction_id)
    "twitter_interactions_tweet_id_key" UNIQUE, btree (tweet_id)
    "index_twitter_interactions_on_created_at" btree (created_at)
    "index_twitter_interactions_on_screen_name" btree (screen_name)
Triggers:
    insert_twitter_interactions_trigger BEFORE INSERT ON twitter_interactions FOR EACH ROW EXECUTE PROCEDURE twitter_interactions_insert_trigger()
Number of child tables: 9 (Use \d+ to list them.)
François Beausoleil
quelle

Antworten:

13

Ich würde in Betracht ziehen, auf den UUID-Typ zu wechseln. char(36)dauert 40 Bytes, uuiddauert 16, so dass Sie 24 Bytes pro Zeile sparen, was für Sie 12 MB pro Tag entspricht, 4 GB nach einem Jahr. Plus-Indizes. Je nachdem, welche Hardware Sie haben, ist das nicht viel, aber es könnte sein. Und es summiert sich, wenn Sie mehr Verbesserungsmöglichkeiten haben.

Außerdem sehe ich in Ihrem Schema keine Einschränkung, die sicherstellt, dass interaction_ides tatsächlich das richtige Format hat. Wenn Sie den richtigen Typ verwenden, erhalten Sie dies ebenfalls.

Wenn Sie dies jedoch mögen, bigintwürde die Verwendung noch mehr sparen und eine noch bessere Leistung erzielen. Es ist sehr unwahrscheinlich, dass Ihre Anwendung so groß ist, dass eine bigintfür eine ID-Spalte nicht funktioniert.

Peter Eisentraut
quelle
Ich habe ein verteiltes System: Mehrere Datenquellen generieren IDs für die Interaktionen. Daher kann ich kein einfaches BIGINT verwenden, es sei denn, ich habe N Bits für die Knoten-ID reserviert.
François Beausoleil
3
@ FrançoisBeausoleil: Das Reservieren von N Bits für die Knoten-ID entspricht der Verwendung jeder N-ten Nummer in einer Sequenz (und ist daher einfach zu implementieren). Sie können auch die Verwendung von zusammengesetzten Schlüsseln in Betracht ziehen.
Unbilliger
1
Das Koordinieren mehrerer Sequenzen (mit der Node-ID) ist in der Praxis ein administrativer Aufwand und fehleranfällig. Ich sehe keinen Grund, in diesem Szenario keine UUIDs zu verwenden, zumal Bits heutzutage billig sind (sowohl Speicher als auch Speicher). In der Tat ist dieses Szenario genau der Grund, warum UUIDs vor Jahrzehnten erfunden wurden: Daten zwischen verteilten Systemen ohne zentralisierte Koordination auszutauschen .
Basil Bourque
6

Ich bin kein Postgres-Mensch, aber basierend auf dem, was ich von SQL Server kenne, ist die Leistung, die Sie haben werden, umso besser, je mehr Zeilen Sie auf eine Datenseite passen (das Lesen von Daten von der Festplatte ist in der Regel) die teuerste Operation). Der Wechsel von einem 36 ish 1 Byte breiten Feld zu einer 16 Byte großen GUID scheint also eine einfache Kostenersparnis zu sein. Je weniger Lesevorgänge Sie durchführen können, desto schneller können Sie Ergebnisse zurückgeben. All dies setzt natürlich voraus, dass eine GUID / UUID die Geschäftsanforderungen der Tabelle erfüllt. Wenn eine UUID diese erfüllt, würde a Bigint ? Das würde Ihre Speicherkosten um weitere 8 Byte pro Zeile senken.

Bearbeiten 1

Für Zeichendaten in Postgres fallen zusätzliche Speicherkosten an. Kurze Zeichenfolgen mit weniger als 127 Bytes haben einen 1-Byte-Overhead, während längere 4 Bytes haben, so dass der zweite Befragte 40-Byte-Kosten für ein 36-Byte-Feld errechnet hat. Es gibt jedoch auch eine Option für die String-Komprimierung, sodass möglicherweise nicht die vollen 40 ausgegeben werden. Ich kann die endgültigen Kosten nicht abschätzen, aber die Grundlagen bleiben erhalten: Alles über 16 Byte erhöht die Speicherkosten. Das Lesen dauert länger und verbrauchen mehr Speicher.

Die Speicheranforderung für eine kurze Zeichenfolge (bis zu 126 Byte) beträgt 1 Byte plus der tatsächlichen Zeichenfolge, einschließlich der Leerzeichenauffüllung bei Zeichen. Längere Zeichenfolgen haben 4 Byte Overhead anstelle von 1. Lange Zeichenfolgen werden vom System automatisch komprimiert, sodass die physischen Anforderungen auf der Festplatte möglicherweise geringer sind.

billinkc
quelle
3

Beachten Sie neben dem Platzproblem, dass Sie jede Tabelle ändern müssen, um den richtigen Datentyp zu verwenden. Andernfalls wird die Join-Leistung schlecht.

mrdenny
quelle
Das war selbstverständlich, aber danke, dass Sie mich daran erinnert haben.
François Beausoleil
3
Wenn ich so große Änderungen vornehme, zahlt es sich normalerweise aus, alles aufzuschreiben (egal wie einfach es ist, sich an etwas zu erinnern).
Mrdenny
3

Neben der Einsparung von Daten und Indizes (wie von anderen gesagt), die sich in Einsparungen bei den E / A-Vorgängen niederschlägt, müssen Sie berücksichtigen, wie Sie neue Werte generieren interaction_idund welche Auswirkungen dies auf das System haben wird Indizes und Abfragebedingungen (Joins).

Für den Index ist er kleiner. Wenn jedoch viele Ihrer Abfragen Index-Scans verwenden, kann das Umschalten auf UUIDs Index-Scans unmöglich machen (abhängig davon, wie Sie UUIDs generieren) und ist bigintmöglicherweise die bessere Wahl.

Schließlich hängt die tatsächliche Auswirkung auf die Leistung auch von Ihren Nutzungsmustern ab und der Datenverteilung , sollten Sie Tests durchführen und über eine Entwicklungs- und Testumgebung verfügen, in der Sie Ihre Änderungen testen können.

Auf diese Weise erhalten Sie eine genauere Antwort auf die Auswirkungen auf die Leistung.

Unvernunft
quelle
Vielen Dank für den nützlichen Beitrag und willkommen auf der Website :)
Jack Douglas
Meine Zugriffsmuster beziehen sich auf Datumsbereiche, JOIN mit dem Benutzernamen oder über die UUID. Es werden keine Bereichsüberprüfungen der eindeutigen ID erwartet. Vielen Dank für Ihre Antwort, sehr informativ.
François Beausoleil