큰 텍스트 답변에서 PostgreSQL에서 고유 인덱스를 빌드하는 방법: SHA512가 SHA256보다 빠릅니까?
이를 수행하는 한 가지 방법은 Rails가 다음과 같은 문을 모델링하는지 확인하는 것입니다.
validates username, uniqueness: true
PostgreSQL의 실제unique indexes에 해당합니다.
그 두 가지 이유:
오늘날 데이터베이스가 단일 앱에서만 사용된다고 해도 미래에는 둘 이상이 있을 수 있으며 기존 테이블에 인덱스를 추가하거나 큰 테이블에서 중복 행을 정리해야 하는 것은 항상 약간의 고통입니다(잠금 때문에 그것에 대해 다른 기사를 작성할 수도 있습니다..).
그때 무슨 일이 있었나요?
그것은 곧은 것 같죠? 인덱스가 필요한 열을 나열하고, 이에 대한 Rails 마이그레이션을 작성하고, 마이그레이션을 실행하고, 잊어버리십시오.
무작위 테스트가 문자 그대로 나를 감독에서 구한 곳입니다.
RSS 피드에서 20개 이상의 항목을 가져와 기사로 변환하고 DB에 삽입한 다음 개수를 확인하여 일치하는지 확인하는 테스트가 코드베이스에 있습니다.
그것들은 모두 다른 기사이지만 데이터베이스는 어쨌든 고유한지 확인할 것입니다(명백한 이유로).
카운트가 일치하지 않았고 매우 심각한 디버깅 마술(일명 중단점 설정 및 인쇄 항목) 후에 다음을 발견했습니다.
[1] pry(#<RssReader>)> p e
#<ActiveRecord::StatementInvalid: PG::ProgramLimitExceeded: ERROR: index row size 7280 exceeds btree version 4 maximum 2704 for index "index_articles_on_body_markdown_and_user_id_and_title"
DETAIL: Index row references tuple (8,1) in relation "articles".
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.
: INSERT INTO "articles" ("body_markdown", "boost_states", "cached_tag_list", "cached_user", "cached_user_name", "cached_user_username", "created_at", "description", "feed_source_url", "password", "path", "processed_html", "published_from_feed", "reading_time", "slug", "title", "updated_at"
무엇을 기다립니다!?
약간의 파기 후에 나는 내 부주의를 깨달았습니다. 인덱싱할 텍스트가 너무 크고 PostgreSQL 버퍼 페이지에 맞지 않으면 인덱싱이 작동하지 않을 것입니다.
PostgreSQL 버퍼 페이지 크기는 확대될 수 있지만 이는 요점을 벗어나는 것이며 좋은 생각도 아닙니다.
그래서 해결책은 무엇입니까?
해결책은 열의 해시를 만들고 열 자체 대신 인덱스를 만드는 것입니다.
이에 대해 여러 가지 방법이 있지만 이것이 우리의 특정 상황에 대해 선택한 것입니다.
CREATE UNIQUE INDEX CONCURRENTLY "index_articles_on_digest_body_markdown_and_user_id_and_title"
ON "articles"
USING btree (digest("body_markdown", 'sha512'::text), "user_id", "title");
분해해 보겠습니다.
CREATE UNIQUE INDEX
는 설명이 필요 없습니다. 동일한 값을 두 번 삽입할 수 없도록 열에 인덱스를 생성합니다CONCURRENTLY
는 PostgreSQL 영역에서 큰 변화입니다. 간단히 말해서 백그라운드에서 인덱스를 비동기적으로 추가합니다. 기본적으로 인덱스가 작성되는 동안 테이블에 대한 작업을 차단하지 않습니다. btree
는 standard default index for PostgreSQLdigest("body_markdown", 'sha512'::text)
는 마법이 일어나는 곳입니다. 우리는 PostgreSQL에게 SHA512 해시를 생성하도록 지시하고(MD5 😅) 인덱스 비교를 위해 그것을 사용합니다"user_id", "title"
단일 컬럼에 대한 인덱스가 아니라 멀티 컬럼 인덱스데이터베이스에 값을 두 번 추가하려고 하면 다음과 같이 됩니다.
$ pgcli PracticalDeveloper_development
PracticalDeveloper_development> insert into articles (body_markdown, user_id, title, created_at, updated_at) select body_markdown, user_id, title, now(), now() from articles order by random() limit 1;
duplicate key value violates unique constraint "index_articles_on_digest_body_markdown_and_user_id_and_title"
DETAIL: Key (digest(body_markdown, 'sha512'::text), user_id, title)=(\x1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75, 10, The Curious Incident of the Dog in the Night-Time Voluptas quia) already exists.
일반 psql 대신 사용하는 pgcli에 대한 보너스 팁
이 조사의 결과는 .
Reference
이 문제에 관하여(큰 텍스트 답변에서 PostgreSQL에서 고유 인덱스를 빌드하는 방법: SHA512가 SHA256보다 빠릅니까?), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/rhymes/how-to-build-unique-indexes-in-postgresql-on-large-text-3e6d텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)