[[["易于理解","easyToUnderstand","thumb-up"],["解决了我的问题","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["很难理解","hardToUnderstand","thumb-down"],["信息或示例代码不正确","incorrectInformationOrSampleCode","thumb-down"],["没有我需要的信息/示例","missingTheInformationSamplesINeed","thumb-down"],["翻译问题","translationIssue","thumb-down"],["其他","otherDown","thumb-down"]],["最后更新时间 (UTC):2025-09-05。"],[],[],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)."]]