Eu não sou muito bom com DB, por favor, tenha paciência comigo.
Estou tentando colocar dados JSON muito longos em uma tabela, esta tabela foi criada pelo framework Django.
Estou usando o Postgres no Heroku. Então, quando tento colocar os dados, recebo o seguinte erro:
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.
Meu banco de dados e tabela são mais ou menos assim:
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)
Parece que eu tenho que mudar "editor_contentmodel_content_2192f49c_uniq" UNIQUE CONSTRAINT, btree (content, ref_id)
para tirarmd5(content)
Alguém pode me ajudar com isso? Não tenho idéia de como fazê-lo.
Atualizar:
JSON
content - https://gist.github.com/akshaybabloo/0b3dc1fb4d964b10d09ccd6884fe3a40
Atualização 2:
Eu criei o seguinte UNIQUE
índice, o que devo remover neste?
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
Devo remover 1
ou 2
(veja as setas)?
postgresql
akshay
fonte
fonte
Respostas:
Você tem um índice UNIQUE
(content, ref_id)
, chamadoeditor_contentmodel_content_2192f49c_uniq
Não sei por que isso está aí para começar. Então, vamos voltar e abordar o que isso faz. Isso garante
content
eref_id
é único. No entanto, no PostgreSQL, aUNIQUE
restrição é implementada com uma btree, o que a torna uma solução ruim. Usando esse método, você está criando uma btree com conteúdo que duplica essencialmente o tamanho dessa pequena tabela e cria um índice gigantesco. Um índice gigantesco que ainda é limitado pelo tamanho do conteúdo - como você encontrou. Isso levanta algumas questõesVocê se importa que o conteúdo seja único? Se você se importa que o conteúdo seja exclusivo para ref_id, o que você provavelmente quer é armazenar o hash do conteúdo. Algo como..
Em vez disso, ele armazenará o md5sum de conteúdo na btree. Desde que ref_id tenha conteúdo com um md5 exclusivo sobre esse ref_id, você estará bem.
Se você não se importa com isso,
content
considere removê-lo completamente.Pode não valer nada que, ao implementar uma
UNIQUE
restrição com uma btree (como o PostgreSQL faz), você obtém um índice adicionado gratuitamente. Sob uma circunstância normal, isso tem um benefício adicional.Acelerará a consulta
No entanto, quando você tiver a chance de usar a
md5()
variante funcional, não haverá mais um índice no conteúdo; portanto, agora, para usar esse índice, você precisarámd5(content) = md5('This content')
O todo
text = text
está superestimado. Isso quase nunca é o que você deseja. Se você deseja acelerar o tempo de consulta sobre o texto, o btree é bastante inútil. Você provavelmente quer investigarATUALIZAÇÃO 1
Baseando-se no seu JSON , sugiro armazená-lo como um
jsonb
e criar o índicemd5(content)
; então, talvez, ao invés do acima, execute isso.ATUALIZAÇÃO 2
Você pergunta quais índices você deve remover
Aqui está a resposta surpreendente: você deve remover todos eles, exceto : o
editor_contentmodel_pkey
que diz que todosref_id
precisam ser únicos.editor_contentmodel_content_2192f49c_uniq
esse índice garante que você estejaUNIQUE
noref_id
ANDcontent
, mas se não puder ter uma duplicata,ref_id
nunca poderá ter um conteúdo duplicado para issoref_id
. Portanto, você nunca pode violar esse índice sem violar tambémeditor_contentmodel_pkey
. Isso torna inútil.editor_contentmodel_ref_id_md5_idx
esse índice também não faz sentido pelo mesmo motivo. Você nunca pode ter uma duplicatamd5(content::text)
maisref_id
porque, independentemente do que o valor demd5(content::text)
é que você nunca pode ter uma duplicataref_id
.editor_contentmodel_ref_id_8f74b4f3_like
também é uma má ideia, porque você está duplicando o índiceref_id
. Isso não é inútil, apenas não é o ideal. Em vez disso, se você precisar,varchar_pattern_ops
use apenas ocontent
campo.Como última nota, não usamos muito
varchar
no PostgreSQL porque ele é implementado como uma varlena com uma restrição de verificação. Não há ganho para isso e não há nada perdido quando você simplesmente usatext
. Portanto, a menos que haja uma razão concreta para queref_id
possa haver 120 caracteres, mas 119 caracteres, eu simplesmente usaria otext
tipoATUALIZAÇÃO 3
Vamos voltar ao seu problema anterior.
Isso está dizendo que o problema está especificamente no índice
"editor_contentmodel_content_2192f49c_uniq"
. Você definiu isso comoPortanto, o problema aqui é que você está tentando criar um índice novamente
content
. Mas, novamente, o próprio índice armazena o conteúdo json real decontent
e é isso que excede o limite. Isso não é realmente um problema, porque mesmo se esse limite não estivesse em vigor,editor_contentmodel_content_2192f49c_uniq
seria totalmente inútil. Por quê? novamente, você não pode adicionar mais exclusividade a uma linha que já é garantida como 100% exclusiva. Você não parece estar entendendo isso. Vamos simplificar.No exemplo acima, um único índice / restrição único (sem outros índices)
(ref_id, content)
faz sentido porque interromperia a duplicação de(1,1)
. Um excesso de índice(ref_id, md5(content))
também faria sentido, pois interromperia a duplicação de(1,1)
por proxy de interromper a duplicação de(1, md5(1))
. No entanto, tudo isso funciona, porque no exemplo que eu dei NÃOref_id
é garantido . Seu não é isso . SeuUNIQUE
ref_id
ref_id
ref_id
é umPRIMARY KEY
. Isso significa que é garantido que seja ÚNICO.Isso significa que a duplicata
(1,1)
e a linha(1,2)
NUNCA poderão ser inseridas. Isso também significa que índices além de ref_id não podem garantir mais exclusividade. Eles teriam que ser menos rigorosos que o índice que você possui atualmente. Portanto, sua mesa só poderia ficar assimfonte
editor_contentmodel
tabelascolumn
e adicionar exclusividade md5 a ela? ou não podemos simplesmente alterarCONSTRAINT editor_contentmodel_content_2192f49c_uniq UNIQUE (content, ref_id)
? Por que eu tenho que criar uma nova tabela para isso?CREATE TABLE
comando e emitaCREATE UNIQUE INDEX
logo abaixo. EntãoDROP
seu índice antigo.Update 2
Como ref_id é a chave primária, você não pode ter valores duplicados. Isso significa que a restrição exclusiva na combinação (content, ref_id) é inútil, pois qualquer coisa que viole isso também violaria a restrição da chave primária. apenas livre-se disso.
fonte
create unique index on editor_contentmodel (ref_id, md5(content::text))
? ou eu poderia recriar a tabela e remover a chave primária.