Je ne suis pas très bon avec DB, alors soyez indulgent avec moi.
J'essaie de mettre une très longue donnée JSON dans une table, cette table a été créée par le framework Django.
J'utilise Postgres sur Heroku. Ainsi, lorsque j'essaie de mettre les données, j'obtiens l'erreur suivante:
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.
Ma base de données et ma table ressemblent à ceci:
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)
On dirait que je dois changer "editor_contentmodel_content_2192f49c_uniq" UNIQUE CONSTRAINT, btree (content, ref_id)
pour prendremd5(content)
Est-ce que quelqu'un peut m'aider avec ça? Je n'ai aucune idée de comment le faire.
Mise à jour:
JSON
contenu - https://gist.github.com/akshaybabloo/0b3dc1fb4d964b10d09ccd6884fe3a40
Mise à jour 2:
J'ai créé l' UNIQUE
index suivant , que dois-je supprimer ici?
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
Dois-je retirer 1
ou 2
(Voir les flèches)?
la source
Réponses:
Vous avez un index UNIQUE
(content, ref_id)
, appeléeditor_contentmodel_content_2192f49c_uniq
Je ne sais pas pourquoi cela là pour commencer. Revenons donc en arrière et examinons ce que cela fait. Cela garantit cela
content
etref_id
est unique. Cependant, dans PostgreSQL, laUNIQUE
contrainte est implémentée avec un btree, ce qui en fait une mauvaise solution. En utilisant cette méthode, vous créez un btree avec un contenu qui duplique essentiellement la taille de cette petite table et crée un index gigantesque. Un index gigantesque qui est toujours limité par la taille du contenu, comme vous l'avez trouvé. Cela soulève quelques questionsVous souciez-vous que le contenu soit unique? Si vous vous souciez du fait que le contenu est unique pour ref_id, alors ce que vous voulez probablement est de stocker le hachage du contenu. Quelque chose comme..
Cela stockera à la place la somme md5 du contenu sur le btree. Tant que ref_id a du contenu avec un md5 unique sur ce ref_id, vous êtes bon.
Si vous ne vous souciez pas de cela,
content
pensez à le supprimer entièrement.Cela ne vaut peut-être rien que lorsque vous implémentez une
UNIQUE
contrainte avec un btree (comme le fait PostgreSQL), vous obtenez un index supplémentaire gratuitement. Dans des circonstances normales, cela présente un avantage marginal.Accélérera la requête
Cependant, lorsque vous avez la possibilité d'utiliser la
md5()
variante fonctionnelle, il n'y a plus d'index sur le contenu, alors maintenant, pour utiliser cet index, vous devrezmd5(content) = md5('This content')
L'ensemble
text = text
est surévalué. Ce n'est presque jamais ce que tu veux. Si vous cherchez à accélérer le temps de requête sur le texte, le btree est assez inutile. Vous voudrez probablement examinerMISE À JOUR 1
Sur la base de votre JSON, je suggère de le stocker en tant que
jsonb
, puis de créer l'indexmd5(content)
; alors peut-être que plutôt que ci-dessus exécutez cela.MISE À JOUR 2
Vous demandez quels index vous devez supprimer
Voici la réponse surprenante: vous devez tous les supprimer sauf :
editor_contentmodel_pkey
qui dit que toutref_id
doit être unique.editor_contentmodel_content_2192f49c_uniq
cet index garantit que vous êtesUNIQUE
surref_id
ANDcontent
, mais si vous ne pouvez pas avoir de doublon,ref_id
vous ne pouvez jamais avoir de contenu en double pour celaref_id
. Vous ne pouvez donc jamais violer cet index sans violer égalementeditor_contentmodel_pkey
. Cela le rend inutile.editor_contentmodel_ref_id_md5_idx
cet indice est également inutile pour la même raison. Vous ne pouvez jamais avoir un doublemd5(content::text)
surref_id
parce que quelle que soit la valeur demd5(content::text)
c'est que vous ne pouvez jamais avoir un doubleref_id
.editor_contentmodel_ref_id_8f74b4f3_like
est également une mauvaise idée car vous dupliquez l'indexref_id
. Ce n'est pas inutile, c'est tout simplement pas optimal. Au lieu de cela, si vous en avez besoin,varchar_pattern_ops
utilisez-le plutôt que sur lecontent
terrain.Enfin, nous n'utilisons pas beaucoup
varchar
dans PostgreSQL car il est implémenté comme une varlena avec une contrainte de vérification. Il n'y a aucun gain à cela, et il n'y a rien de perdu lorsque vous utilisez simplementtext
. Donc, à moins qu'il n'y ait une raison concrète pour laquelle ilref_id
peut jamais y avoir 120 caractères mais il peut être de 119 caractères, alors j'utiliserais simplement letext
type.MISE À JOUR 3
Revenons à votre problème précédent ..
Cela vous indique que le problème concerne spécifiquement l' index
"editor_contentmodel_content_2192f49c_uniq"
. Vous l'avez défini commeLe problème ici est que vous essayez de créer un index
content
. Mais, encore une fois, l'index lui-même stocke le contenu json réel decontent
, et c'est ce qui dépasse la limite. Ce n'est pas vraiment un problème, car même si cette limite n'était pas en place, elleeditor_contentmodel_content_2192f49c_uniq
serait totalement inutile. Pourquoi? encore une fois, vous ne pouvez pas ajouter plus d'unicité à une ligne qui est déjà garantie à 100% unique. Vous ne semblez pas comprendre cela. Restons simples.Dans ce qui précède, un seul index / contrainte unique (sans aucun autre index)
(ref_id, content)
est logique car cela arrêterait la duplication de(1,1)
. Un index au-dessus(ref_id, md5(content))
aurait également un sens car il arrêterait la duplication de(1,1)
par proxy d'arrêter la duplication de(1, md5(1))
. Cependant, tout cela fonctionne parce que dans l'exemple que j'ai donné, ceref_id
n'est PAS garantiUNIQUE
. Ceref_id
n'est pas çaref_id
. Votreref_id
est unPRIMARY KEY
. Cela signifie qu'il est garanti d'être UNIQUE.Cela signifie que le doublon
(1,1)
et la ligne de(1,2)
ne pourraient JAMAIS être insérés. Cela signifie également que les index sur n'importe quoi en plus de ref_id ne peuvent pas garantir plus d'unicité. Ils devraient être moins stricts que l'indice que vous avez actuellement. Donc, votre table ne pourrait ressembler à cecila source
editor_contentmodel
tablescolumn
et y ajouter l'unicité md5? ou ne pouvons-nous pas simplement modifierCONSTRAINT editor_contentmodel_content_2192f49c_uniq UNIQUE (content, ref_id)
? Pourquoi dois-je créer une nouvelle table pour cela?CREATE TABLE
commande et lancez leCREATE UNIQUE INDEX
droit en dessous. Ensuite,DROP
votre ancien index.Update 2
Puisque ref_id est la clé primaire, vous ne pouvez pas en avoir de valeurs en double. Cela signifie que la contrainte unique sur la combinaison (contenu, ref_id) est inutile, car tout ce qui viole violerait également la contrainte de clé primaire. Débarrassez-vous-en.
la source
create unique index on editor_contentmodel (ref_id, md5(content::text))
? ou je pourrais recréer la table et supprimer la clé primaire.