バッファーページの1/3より大きい値はインデックス付けできません


9

私はDBがあまり得意ではないので、我慢してください。

非常に長いJSONデータをテーブルに配置しようとしています。このテーブルはDjangoフレームワークによって作成されました。

HerokuでPostgresを使用しています。したがって、データを配置しようとすると、次のエラーが発生します。

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.

私のDBとテーブルは次のようになります。

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)

私は"editor_contentmodel_content_2192f49c_uniq" UNIQUE CONSTRAINT, btree (content, ref_id)取るために変更する必要があるようですmd5(content)

誰かがこれを手伝ってくれる?どうすればいいのかわかりません。

更新:

JSONコンテンツ-https://gist.github.com/akshaybabloo/0b3dc1fb4d964b10d09ccd6884fe3a40

アップデート2:

次のUNIQUEインデックスを作成しましたが、これで何を削除する必要がありますか?

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

1または2(矢印を参照)を削除する必要がありますか?


あなたはTEXT列にインデックスを付けようとします、そしてPostgreSQL(他のすべてと同様に)には2713というインデックスのための制限があります、そうです-それを小さくするためにMD5ハッシュのためにそれを変更しようとすることができます
a_vlad

@a_vladどうすればいいですか?それを行う方法についてはわかりません。
akshay

コンテンツとは何ですか?それはTEXTかJSONですか?
エヴァンキャロル

また、同じref_idに対して2つのコンテンツがあることはありますか?もしそうなら、その目的は何ですか?
エヴァンキャロル

@EvanCarrollに同意します-あなたはこのインデックスをまったく必要としませんか?
a_vlad 2017

回答:


7

あなたは上のUNIQUEインデックス持っている(content, ref_id)と呼ばれるが、editor_contentmodel_content_2192f49c_uniq

"editor_contentmodel_content_2192f49c_uniq" UNIQUE CONSTRAINT, btree (content, ref_id)

これがそもそもなぜあるのか、よくわかりません。それでは、一歩下がって、これが何をするかを説明しましょう。これはcontent、とref_idが一意であることを確認します。ただし、PostgreSQLでは、UNIQUE制約がbtreeで実装されているため、これは解決策としては不十分です。この方法を使用して、この小さなテーブルのサイズを本質的に複製するコンテンツを持つbtreeを作成し、巨大なインデックスを作成します。ただし、コンテンツサイズによって制限されている巨大なインデックスです。それはいくつかの質問を提起します

  • コンテンツがユニークであることを気にしますか?コンテンツがref_idに対して一意であることを気にしている場合は、おそらくコンテンツのハッシュを保存することをお勧めします。何かのようなもの..

    CREATE TABLE foo ( ref_id int, content text );
    CREATE UNIQUE INDEX ON foo (ref_id,md5(content));

    代わりに、コンテンツのmd5sumをbtreeに保存します。ref_idに、そのref_idよりも固有のmd5を持つコンテンツがある限り、問題ありません。

  • それcontentがユニークであることが気にならない場合は、完全に削除することを検討してください。

UNIQUE(PostgreSQLのように)btreeを使用して制約を実装すると、追加のインデックスが無料で得られることは何の価値もありません。通常の状況では、これには限界があります。

CREATE TABLE foo ( ref_id int, content text );
CREATE UNIQUE INDEX ON foo (ref_id,content);

クエリを高速化します

SELECT *
FROM foo
WHERE ref_id = 5
  AND content = 'This content'

ただし、機能md5()バリアントを使用する可能性がある場合は、コンテンツのインデックスが存在しないため、そのインデックスを使用するには、次の操作を行う必要があります。

  1. ref_idに対するクエリのみ
  2. ref_idに次の句を追加します md5(content) = md5('This content')

全体text = textが過大評価されています。それはあなたが望むものではほとんどありません。テキストのクエリ時間を短縮したい場合、btreeはほとんど役に立ちません。調べたくなるでしょう

  1. pgtrgm
  2. text_pattern_ops
  3. 全文検索(FTS)

アップデート1

JSONに基づいて、それをとして保存しjsonb、次にインデックスを作成することをお勧めしmd5(content)ます。したがって、おそらく上記の代わりにこれを実行します。

ALTER TABLE public.editor_contentmodel
  ALTER COLUMN content
  SET DATA TYPE jsonb
  USING content::jsonb;

CREATE UNIQUE INDEX ON foo (ref_id,md5(content::text));

アップデート2

削除するインデックスを尋ねます

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

ここに驚くべき答えがあります:すべてを一意にする必要があると言うことを除いて、それらすべて削除する必要があります:editor_contentmodel_pkeyref_id

  1. editor_contentmodel_content_2192f49c_uniqこのインデックスは、あなたがしていることを確認しますUNIQUEref_idcontentしますが、重複して持つことができない場合はref_id、あなたがそのために重複したコンテンツを持っていることはありませんがref_id。したがって、違反することなく、このインデックスに違反することはできませんeditor_contentmodel_pkey。それは無意味になります。
  2. editor_contentmodel_ref_id_md5_idxこのインデックスも同じ理由で無意味です。あなたは、重複したということはありませんmd5(content::text)以上をref_id関係なく、値が何のためmd5(content::text)であるあなたは、重複を持つことはできませんref_id
  3. editor_contentmodel_ref_id_8f74b4f3_likeインデックスを複製しているため、これも悪い考えですref_id。これは役に立たないわけではなく、最適ではありません。代わりに、フィールドvarchar_pattern_opsだけで使用する必要がある場合content

最後にvarchar、チェック制約付きのvarlenaとして実装されているため、PostgreSQL ではあまり使用しません。それに利益はなく、単にを使用しても何も失われませんtext。したがって、ref_id120文字にすることができるが119文字にすることができる具体的な理由がない限り、単純にtextタイプを使用します。

アップデート3

以前の問題に戻りましょう。

psycopg2.OperationalError: index row size 3496 exceeds maximum 2712 for index "editor_contentmodel_content_2192f49c_uniq"

これは、問題が特にインデックスにあること"editor_contentmodel_content_2192f49c_uniq"を示しています。あなたはそれを次のように定義しました

"editor_contentmodel_content_2192f49c_uniq" UNIQUE CONSTRAINT, btree (content, ref_id)

したがって、ここでの問題は、にインデックスを作成しようとしていることですcontent。ただし、繰り返しになりますが、インデックス自体にはの実際のjsonコンテンツが格納されており、それcontentが制限を超えています。これは実際には問題ではありません。制限が設けられていなくてeditor_contentmodel_content_2192f49c_uniqも、まったく役に立たないからです。どうして?この場合も、すでに100%一意であることが保証されている行に一意性を追加することはできません。あなたはこれを得ていないようです。シンプルにしましょう。

ref_id | content
1      | 1
1      | 1
1      | 2
2      | 1

上記では、(他のインデックスがない)唯一の一意のインデックス/制約(ref_id, content)は、の複製を停止するため、意味があり(1,1)ます。インデックス (ref_id, md5(content))の複製も、の複製を停止する代わりにの複製を停止するため、意味(1,1)があり(1, md5(1))ます。しかし、この作品のすべてのための例では私が与えてくれたref_idれないことが保証しますUNIQUE。あなたref_idはこれではないref_id。あなたref_idPRIMARY KEYです。つまり、一意であることが保証されます。

つまり、複製(1,1)と行を(1,2)挿入することはできません。つまり、ref_id以外のインデックスは、一意性を保証できません。彼らはあなたが現在持っているインデックスよりも厳格でなければなりません。したがって、テーブルは次のようにしか見えません

ref_id | content
1      | 1
2      | 1

editor_contentmodelテーブルを変更columnしてmd5の一意性を追加することはできませんか?または私たちは単に変更することはできませんCONSTRAINT editor_contentmodel_content_2192f49c_uniq UNIQUE (content, ref_id)か?なぜ新しいテーブルを作成する必要があるのですか?
akshay 2017

新しいテーブルを作成する必要はありません。取得したテーブルの簡易バージョンでどのように見えるかを示しただけでした。CREATE TABLEコマンドを無視して、そのCREATE UNIQUE INDEXすぐ下に発行してください。次にDROP、古いインデックス。
エヴァンキャロル

最後の質問、あなたは私のことを見ることができますUpdate 2
akshay

@akshayが更新されました。
エヴァンキャロル

1
エバンさん、本当にありがとうございました。コンセプトはまだ少し不安定です(私の分野ではありません)。それを学ぼうと思います。
akshay 2017

2

"editor_contentmodel_pkey" PRIMARY KEY、btree(ref_id) "editor_contentmodel_content_2192f49c_uniq" UNIQUE CONSTRAINT、btree(content、ref_id)

ref_idは主キーであるため、値を重複させることはできません。これは、組み合わせに固有の制約(content、ref_id)は役に立たないことを意味します。違反するものはすべて、主キー制約にも違反するためです。それを取り除くだけです。


あなたはそれを取り除き、何かを置くことを意味しますcreate unique index on editor_contentmodel (ref_id, md5(content::text))か?または、テーブルを再作成して主キーを削除することもできます。
akshay 2017

あなたが何をしたいのか分かりません。ref_idの主キーが必要な場合は、そのままにしておきます。ただし、そのままにしておくと、editor_contentmodel_content_2192f49c_uniqは役に立たなくなり、ドロップするとタイトルの問題が解決します。また、主キーを保持すると、提案する新しいインデックスも役に立たなくなります(制約としては役に立たないため、インデックスとしては役立つかもしれませんが、それはほとんどありません)。
jjanes 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.