Ich bin nicht sehr gut mit DB, also bitte ertrage es mit mir.
Ich versuche, sehr lange JSON-Daten in eine Tabelle einzufügen. Diese Tabelle wurde vom Django-Framework erstellt.
Ich benutze Postgres auf Heroku. Wenn ich also versuche, die Daten zu speichern, wird der folgende Fehler angezeigt:
File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
psycopg2.OperationalError: index row size 3496 exceeds maximum 2712 for index "editor_contentmodel_content_2192f49c_uniq"
HINT: Values larger than 1/3 of a buffer page cannot be indexed.
Consider a function index of an MD5 hash of the value, or use full text indexing.
Meine Datenbank und Tabelle sehen ungefähr so aus:
gollahalli-me-django-test::DATABASE=> \dt
List of relations
Schema | Name | Type | Owner
--------+----------------------------+-------+----------------
public | auth_group | table | ffnyjettujyfck
public | auth_group_permissions | table | ffnyjettujyfck
public | auth_permission | table | ffnyjettujyfck
public | auth_user | table | ffnyjettujyfck
public | auth_user_groups | table | ffnyjettujyfck
public | auth_user_user_permissions | table | ffnyjettujyfck
public | django_admin_log | table | ffnyjettujyfck
public | django_content_type | table | ffnyjettujyfck
public | django_migrations | table | ffnyjettujyfck
public | django_session | table | ffnyjettujyfck
public | editor_contentmodel | table | ffnyjettujyfck
(11 rows)
gollahalli-me-django-test::DATABASE=> \d+ editor_contentmodel
Table "public.editor_contentmodel"
Column | Type | Modifiers | Storage | Stats target | Description
-----------+--------------------------+-----------+----------+--------------+-------------
ref_id | character varying(120) | not null | extended | |
content | text | not null | extended | |
timestamp | timestamp with time zone | not null | plain | |
Indexes:
"editor_contentmodel_pkey" PRIMARY KEY, btree (ref_id)
"editor_contentmodel_content_2192f49c_uniq" UNIQUE CONSTRAINT, btree (content, ref_id)
"editor_contentmodel_ref_id_8f74b4f3_like" btree (ref_id varchar_pattern_ops)
Es sieht so aus, als müsste ich mich ändern "editor_contentmodel_content_2192f49c_uniq" UNIQUE CONSTRAINT, btree (content, ref_id)
, um zu nehmenmd5(content)
Kann mir jemand dabei helfen? Ich habe keine Ahnung, wie es geht.
Aktualisieren:
JSON
Inhalt - https://gist.github.com/akshaybabloo/0b3dc1fb4d964b10d09ccd6884fe3a40
Update 2:
Ich habe den folgenden UNIQUE
Index erstellt. Was soll ich dabei entfernen?
gollahalli_me_django=> create unique index on editor_contentmodel (ref_id, md5(content::text));
CREATE INDEX
gollahalli_me_django=> \d editor_contentmodel;
Table "public.editor_contentmodel"
Column | Type | Modifiers
-----------+--------------------------+-----------
ref_id | character varying(120) | not null
content | jsonb | not null
timestamp | timestamp with time zone | not null
Indexes:
"editor_contentmodel_pkey" PRIMARY KEY, btree (ref_id)
"editor_contentmodel_content_2192f49c_uniq" UNIQUE CONSTRAINT, btree (content, ref_id) <---- 1
"editor_contentmodel_ref_id_md5_idx" UNIQUE, btree (ref_id, md5(content::text))
"editor_contentmodel_ref_id_8f74b4f3_like" btree (ref_id varchar_pattern_ops) <----2
Soll ich entfernen 1
oder 2
(siehe die Pfeile)?
quelle
Antworten:
Sie haben einen EINZIGARTIGEN Index mit dem
(content, ref_id)
Nameneditor_contentmodel_content_2192f49c_uniq
Ich bin mir nicht sicher, warum das hier anfängt. Lassen Sie uns also einen Schritt zurücktreten und uns mit dem befassen, was dies bewirkt. Dies stellt sicher, dass
content
undref_id
sind einzigartig. In PostgreSQL wird dieUNIQUE
Einschränkung jedoch mit einem btree implementiert, was dies zu einer schlechten Lösung macht. Mit dieser Methode erstellen Sie einen Baum mit Inhalten, der im Wesentlichen die Größe dieser kleinen Tabelle dupliziert und einen gigantischen Index ergibt. Ein gigantischer Index, der jedoch immer noch durch die Größe des Inhalts begrenzt ist - wie Sie festgestellt haben. Es wirft einige Fragen aufInteressiert es Sie, dass Inhalte einzigartig sind? Wenn Sie sich darum kümmern, dass der Inhalt für ref_id eindeutig ist, möchten Sie wahrscheinlich den Hash des Inhalts speichern . Etwas wie..
Dadurch wird stattdessen die md5sum des Inhalts auf dem btree gespeichert. Solange ref_id über diese ref_id Inhalte mit einem eindeutigen md5 enthält, sind Sie gut.
Wenn es Ihnen egal ist, dass dies
content
einzigartig ist, sollten Sie es vollständig entfernen.Es kann nichts wert sein, dass Sie beim Implementieren einer
UNIQUE
Einschränkung mit einem btree (wie bei PostgreSQL) kostenlos einen zusätzlichen Index erhalten. Unter normalen Umständen hat dies einen Nebeneffekt.Beschleunigt die Abfrage
Wenn Sie jedoch die Möglichkeit haben, die Funktionsvariante zu verwenden,
md5()
gibt es keinen Index mehr für den Inhalt. Um diesen Index jetzt zu verwenden, müssen Sie dies tunmd5(content) = md5('This content')
Das Ganze
text = text
ist überbewertet. Das ist fast nie was du willst. Wenn Sie die Abfragezeit über Text beschleunigen möchten, ist der btree ziemlich nutzlos. Sie möchten wahrscheinlich untersuchenUPDATE 1
Basierend auf Ihrem JSON würde ich vorschlagen, es als zu speichern
jsonb
und dann den Index für zu erstellenmd5(content)
. also vielleicht eher als die oben genannten stattdessen ausführen.UPDATE 2
Sie fragen, welche Indizes Sie entfernen sollen
Hier ist die überraschende Antwort: Sie sollten alle entfernen, außer :
editor_contentmodel_pkey
was besagt, dass alleref_id
einzigartig sein müssen.editor_contentmodel_content_2192f49c_uniq
Dieser Index stellt sicher, dass SieUNIQUE
aufref_id
ANDcontent
stehen. Wenn Sie jedoch kein Duplikatref_id
haben können, können Sie niemals einen doppelten Inhalt dafür habenref_id
. Sie können diesen Index also niemals verletzen, ohne auch zu verletzeneditor_contentmodel_pkey
. Das macht es sinnlos.editor_contentmodel_ref_id_md5_idx
Dieser Index ist aus dem gleichen Grund auch sinnlos. Man kann nie ein Duplikat hatmd5(content::text)
über ,ref_id
weil unabhängig davon , was der Wertmd5(content::text)
ist , dass Sie nie ein Duplikat haben könnenref_id
.editor_contentmodel_ref_id_8f74b4f3_like
ist auch eine schlechte Idee, weil Sie den Index duplizierenref_id
. Das ist nicht nutzlos, es ist einfach nicht optimal. Wenn Sie eine benötigen,varchar_pattern_ops
verwenden Sie sie stattdessen nur über demcontent
Feld.Als letzte Anmerkung verwenden wir
varchar
in PostgreSQL nicht viel, da es als Varlena mit einer Prüfbedingung implementiert ist. Es gibt keinen Gewinn, und es geht nichts verloren, wenn Sie es einfach verwendentext
. Wenn es also keinen konkreten Grund gibt, warumref_id
es jemals 120 Zeichen geben kann, aber 119 Zeichen, dann würde ich einfach dentext
Typ verwenden.UPDATE 3
Kehren wir zu Ihrem früheren Problem zurück.
Dies sagt Ihnen, dass das Problem speziell mit dem Index zusammenhängt
"editor_contentmodel_content_2192f49c_uniq"
. Sie haben das als definiertDas Problem hier ist also, dass Sie versuchen, einen Index zu erstellen
content
. Aber auch hier speichert der Index selbst den tatsächlichen JSON-Inhalt voncontent
, und das ist es, was das Limit überschreitet. Dies ist eigentlich kein Problem, denn selbst wenn diese Grenze nicht vorhandeneditor_contentmodel_content_2192f49c_uniq
wäre, wäre dies völlig nutzlos. Warum? Auch hier können Sie einer Zeile, die bereits zu 100% eindeutig ist, keine weitere Eindeutigkeit hinzufügen. Sie scheinen das nicht zu verstehen. Lassen Sie es uns einfach halten.Oben ist ein einzelner eindeutiger Index / eine einzelne Einschränkung (ohne andere Indizes)
(ref_id, content)
sinnvoll, da dies die Duplizierung von stoppen würde(1,1)
. Ein Index-Over(ref_id, md5(content))
wäre auch deshalb sinnvoll, weil es die Duplizierung von(1,1)
durch Proxy stoppen würde, um die Duplizierung von zu stoppen(1, md5(1))
. All diese Arbeiten jedoch , weil in diesem Beispiel habe ich gegebenref_id
ist nicht garantiert werden kannUNIQUE
. Deinref_id
ist das nichtref_id
. Deinref_id
ist einPRIMARY KEY
. Das heißt, es ist garantiert EINZIGARTIG.Das bedeutet, dass das Duplikat
(1,1)
und die Zeile von(1,2)
NIEMALS eingefügt werden können. Das bedeutet auch, dass Indizes über alles zusätzlich zu ref_id keine größere Eindeutigkeit garantieren können. Sie müssten weniger streng sein als der Index, den Sie derzeit haben. Ihr Tisch könnte also nur so aussehenquelle
editor_contentmodel
Tabellen nicht änderncolumn
und MD5-Eindeutigkeit hinzufügen? oder können wir nicht einfach ändernCONSTRAINT editor_contentmodel_content_2192f49c_uniq UNIQUE (content, ref_id)
? Warum muss ich dafür eine neue Tabelle erstellen?CREATE TABLE
Befehl und geben Sie dasCREATE UNIQUE INDEX
Recht darunter ein. DannDROP
dein alter Index.Update 2
Da ref_id der Primärschlüssel ist, können Sie keine doppelten Werte davon haben. Das bedeutet, dass die eindeutige Einschränkung für die Kombination (Inhalt, ref_id) unbrauchbar ist, da alles, was verletzt wird, auch die Primärschlüsseleinschränkung verletzt. Lass es einfach los.
quelle
create unique index on editor_contentmodel (ref_id, md5(content::text))
? oder ich könnte die Tabelle neu erstellen und den Primärschlüssel entfernen.