Partitionner les index de recherche

Spanner est compatible avec les index de recherche partitionnés et non partitionnés. Cette page explique comment créer un index de recherche partitionné dans Spanner.

Un index non partitionné est créé lorsque la clause PARTITION BY est omise dans la définition de l'index. Dans un index non partitionné, une requête doit lire tous les fractionnements d'index. Cela limite l'évolutivité potentielle des requêtes de recherche en texte intégral.

Les index partitionnés, en revanche, subdivisent l'index en unités plus petites, une pour chaque partition unique. Les requêtes ne peuvent effectuer des recherches que dans une seule partition à la fois, spécifiée par une condition d'égalité dans la clause WHERE. Les requêtes sur des index partitionnés sont généralement plus efficaces que celles sur des index non partitionnés, car Spanner n'a besoin de lire les données que pour une seule partition. Le partitionnement de l'index de recherche est analogue au préfixe de clé d'un index secondaire.

Par exemple, supposons qu'une base de données contienne 1 000 000 de SingerIds et les deux index suivants :

GoogleSQL

CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  SingerId STRING(MAX) NOT NULL,
  ReleaseTimestamp INT64 NOT NULL,
  AlbumTitle STRING(MAX),
  AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN,
  SingerId_Tokens TOKENLIST AS (TOKEN(SingerId)) HIDDEN
) PRIMARY KEY(SingerId, AlbumId);

CREATE SEARCH INDEX AlbumsUnpartitionedIndex
ON Albums(AlbumTitle_Tokens, SingerId_Tokens);

CREATE SEARCH INDEX AlbumsIndexBySingerId
ON Albums(AlbumTitle_Tokens)
PARTITION BY SingerId;

PostgreSQL

CREATE TABLE albums (
  albumid character varying NOT NULL,
  singerid character varying NOT NULL,
  releasetimestamp bigint NOT NULL,
  albumtitle character varying,
  albumtitle_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle)) VIRTUAL HIDDEN,
  singerid_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.token(singerid)) VIRTUAL HIDDEN,
PRIMARY KEY(singerid, albumid));

CREATE SEARCH INDEX albumsunpartitionedindex
ON albums(albumtitle_tokens, singerid_tokens);

CREATE SEARCH INDEX albumsindexbysingerid
ON albums(albumtitle_tokens)
PARTITION BY singerid;

La requête suivante sélectionne l'index AlbumsIndexBySingerId, car elle ne recherche que les données d'un seul chanteur. Ce type de requête utilise généralement moins de ressources.

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SingerId = "singer1"
AND SEARCH(AlbumTitle_Tokens, 'happy')

PostgreSQL

SELECT albumid
FROM albums
WHERE singerid = 'singer1'
AND spanner.search(albumtitle_tokens, 'happy')

Il est également possible de forcer une requête à utiliser AlbumsUnpartitionedIndex pour renvoyer les mêmes résultats. Toutefois, elle utilise plus de ressources, car la requête doit accéder à toutes les divisions d'index et filtrer tous les albums de tous les chanteurs pour trouver le jeton "heureux", plutôt que les divisions correspondant au chanteur singer1 uniquement.

Toutefois, il arrive que l'application doive effectuer une recherche dans tous les albums plutôt que dans ceux d'un chanteur spécifique. Dans ce cas, vous devez utiliser un index non partitionné :

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, 'piano concerto 1')

PostgreSQL

SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'piano concerto 1')

La recommandation générale est d'utiliser la granularité de partitionnement la plus fine qui soit pratique et adaptée à la requête. Par exemple, si l'application interroge une boîte aux lettres où chaque requête est limitée à une boîte aux lettres spécifique, partitionnez l'index de recherche sur l'ID de la boîte aux lettres. Toutefois, si la requête doit effectuer une recherche dans toutes les boîtes aux lettres, un index non partitionné est plus adapté.

Certaines applications peuvent nécessiter plusieurs stratégies de partitionnement pour répondre à leurs besoins de recherche spécifiques. Par exemple, un système de gestion des stocks peut avoir besoin de prendre en charge les requêtes filtrées par type de produit ou par fabricant. De plus, certaines applications peuvent nécessiter plusieurs tris préalables, comme le tri par date de création ou de modification. Dans ces scénarios, il est recommandé de créer plusieurs index de recherche, chacun étant optimisé pour les requêtes correspondantes. L'optimiseur de requêtes Spanner sélectionne automatiquement un index pour chaque requête.

Étapes suivantes