Spanner는 파티션을 나누지 않은 검색 색인과 파티션을 나눈 검색 색인을 모두 지원합니다.
이 페이지에서는 Spanner에서 파티션을 나눈 검색 색인을 만드는 방법을 설명합니다.
색인 정의에서 PARTITION BY 절이 생략되면 파티션을 나누지 않은 색인이 생성됩니다. 파티션을 나누지 않은 색인에서는 쿼리가 모든 색인 분할에서 읽어야 합니다. 이는 전체 텍스트 검색 쿼리의 확장 가능성을 제한합니다.
반면 파티션을 나눈 색인은 색인을 고유한 파티션마다 하나씩 더 작은 단위로 세분화합니다. 쿼리는 WHERE 절의 일치 조건으로 지정된 단일 파티션 내에서만 검색할 수 있습니다. Spanner는 단일 파티션의 데이터만 읽어야 하므로 일반적으로 파티션을 나눈 색인에 대한 쿼리는 파티션을 나누지 않은 색인에 대한 쿼리보다 효율적입니다. 검색 색인 파티셔닝은 보조 색인의 키 프리픽스와 유사합니다.
예를 들어 데이터베이스에 SingerIds 1,000,000개와 다음 색인 2개가 있다고 가정해 보겠습니다.
또한 같은 결과가 반환되도록 AlbumsUnpartitionedIndex를 사용하여 쿼리를 강제로 수행할 수도 있습니다.
하지만 쿼리가 가수 singer1에 해당하는 분할만 액세스하는 것이 아닌 모든 색인 분할에 액세스하고 모든 가수의 모든 앨범을 필터링하여 토큰 'happy'를 찾아야 하므로 더 많은 리소스를 사용합니다.
하지만 애플리케이션에서 특정 가수의 앨범이 아닌 모든 앨범을 검색해야 하는 경우가 있습니다. 이러한 경우 파티션을 나누지 않은 색인을 사용해야 합니다.
일반적으로 쿼리에 실용적이고 적합한 가장 세분화된 파티셔닝을 사용하는 것이 좋습니다. 예를 들어 애플리케이션이 각 쿼리가 특정 메일함으로 제한된 이메일 편지함을 쿼리하는 경우 편지함 ID에서 검색 색인을 파티션합니다. 그러나 쿼리에서 모든 편지함을 검색해야 하는 경우에는 파티션을 나누지 않은 색인이 더 적합합니다.
특정 애플리케이션에는 특정 검색 요구사항이 충족되도록 분할 전략이 여러 개 필요할 수 있습니다. 예를 들어 인벤토리 관리 시스템은 제품 유형 또는 제조업체별로 필터링된 쿼리를 지원해야 할 수 있습니다. 또한 일부 애플리케이션에는 생성 시간 또는 수정 시간별 정렬과 같은 여러 사전 정렬이 필요할 수 있습니다. 이러한 시나리오에서는 각 검색어에 맞게 최적화된 검색 색인을 여러 개 만드는 것이 좋습니다. Spanner 쿼리 최적화 도구는 자동으로 쿼리마다 색인을 선택합니다.
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["이해하기 어려움","hardToUnderstand","thumb-down"],["잘못된 정보 또는 샘플 코드","incorrectInformationOrSampleCode","thumb-down"],["필요한 정보/샘플이 없음","missingTheInformationSamplesINeed","thumb-down"],["번역 문제","translationIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-09-05(UTC)"],[],[],null,["# Partition search indexes\n\n| **Note:** This feature is available with the Spanner Enterprise edition and Enterprise Plus edition. For more information, see the [Spanner editions overview](/spanner/docs/editions-overview).\n\n\u003cbr /\u003e\n\nSpanner supports both unpartitioned and partitioned\n[search indexes](/spanner/docs/full-text-search/search-indexes).\nThis page describes how to create a partitioned search index in\nSpanner.\n\nAn unpartitioned index is created when the `PARTITION BY` clause is omitted in\nthe index definition. In an unpartitioned index, a query needs to read from\nall the index splits. This limits the potential scalability of full-text search\nqueries.\n\nPartitioned indexes, on the other hand, subdivide the index into smaller units,\none for each unique partition. Queries can only search within a single partition\nat a time, specified by an equality condition in the `WHERE` clause. Queries\nagainst partitioned indexes are generally more efficient than queries against\nunpartitioned indexes because Spanner only needs to read data for a\nsingle partition. Partitioning the search index is analogous to the key prefix\nof a secondary index.\n\nFor example, suppose there are 1,000,000 `SingerIds` in a database and the\nfollowing two indexes: \n\n### GoogleSQL\n\n CREATE TABLE Albums (\n AlbumId STRING(MAX) NOT NULL,\n SingerId STRING(MAX) NOT NULL,\n ReleaseTimestamp INT64 NOT NULL,\n AlbumTitle STRING(MAX),\n AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN,\n SingerId_Tokens TOKENLIST AS (TOKEN(SingerId)) HIDDEN\n ) PRIMARY KEY(SingerId, AlbumId);\n\n CREATE SEARCH INDEX AlbumsUnpartitionedIndex\n ON Albums(AlbumTitle_Tokens, SingerId_Tokens);\n\n CREATE SEARCH INDEX AlbumsIndexBySingerId\n ON Albums(AlbumTitle_Tokens)\n PARTITION BY SingerId;\n\n### PostgreSQL\n\n CREATE TABLE albums (\n albumid character varying NOT NULL,\n singerid character varying NOT NULL,\n releasetimestamp bigint NOT NULL,\n albumtitle character varying,\n albumtitle_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle)) VIRTUAL HIDDEN,\n singerid_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.token(singerid)) VIRTUAL HIDDEN,\n PRIMARY KEY(singerid, albumid));\n\n CREATE SEARCH INDEX albumsunpartitionedindex\n ON albums(albumtitle_tokens, singerid_tokens);\n\n CREATE SEARCH INDEX albumsindexbysingerid\n ON albums(albumtitle_tokens)\n PARTITION BY singerid;\n\nThe following query selects the `AlbumsIndexBySingerId` index because it only\nsearches data for a single singer. This type of query typically uses fewer\nresources. \n\n### GoogleSQL\n\n SELECT AlbumId\n FROM Albums\n WHERE SingerId = \"singer1\"\n AND SEARCH(AlbumTitle_Tokens, 'happy')\n\n### PostgreSQL\n\n SELECT albumid\n FROM albums\n WHERE singerid = 'singer1'\n AND spanner.search(albumtitle_tokens, 'happy')\n\nIt's also possible to [force](/spanner/docs/full-text-search/query-overview#index_selection)\na query to use `AlbumsUnpartitionedIndex` to return the same results.\nHowever, it uses more resources, because the query needs to access all index\nsplits and filter through all albums for all singers to find the token \"happy\",\nrather than just the splits corresponding to singer `singer1`.\n\nHowever, there are times when the application needs to search through all of the\nalbums rather than the albums for a specific singer. In these cases, you must\nuse an unpartitioned index: \n\n### GoogleSQL\n\n SELECT AlbumId\n FROM Albums\n WHERE SEARCH(AlbumTitle_Tokens, 'piano concerto 1')\n\n### PostgreSQL\n\n SELECT albumid\n FROM albums\n WHERE spanner.search(albumtitle_tokens, 'piano concerto 1')\n\nThe general recommendation is to use the finest granularity of partitioning\nthat's practical and appropriate for the query. For example, if the application\nqueries an email mailbox where each query is restricted to a specific mailbox,\npartition the search index on the mailbox ID. However, if the query\nneeds to search through all mailboxes, an unpartitioned index is a better fit.\n\nCertain applications might require multiple partitioning strategies to\naccommodate their specific search requirements. For example, an inventory\nmanagement system might need to support queries filtered by product type or\nmanufacturer. Additionally, some applications might need multiple presorts, such\nas sorting by creation or modification time. In these scenarios, it's\nrecommended that you create multiple search indexes, each optimized for the\ncorresponding queries. The Spanner\n[query optimizer](/spanner/docs/query-optimizer/overview) automatically selects\nan index for each query.\n\nWhat's next\n-----------\n\n- Learn about [tokenization and Spanner tokenizers](/spanner/docs/full-text-search/tokenization).\n- Learn about [search indexes](/spanner/docs/full-text-search/search-indexes).\n- Learn about [numeric indexes](/spanner/docs/full-text-search/numeric-indexes)."]]