Práticas recomendadas de SQL

Conforme descrito em Planos de execução de consulta, o compilador SQL transforma uma instrução SQL em um plano de execução usado para receber os resultados da consulta. Nesta página, descrevemos as práticas recomendadas para criar instruções SQL a fim de ajudar o Spanner a encontrar planos de execução eficientes.

As instruções SQL de exemplo mostradas nesta página usam o seguinte esquema de amostra:

GoogleSQL

CREATE TABLE Singers (
 SingerId   INT64 NOT NULL,
 FirstName  STRING(1024),
 LastName   STRING(1024),
 SingerInfo BYTES(MAX),
 BirthDate  DATE
) PRIMARY KEY (SingerId);

CREATE TABLE Albums (
 SingerId     INT64 NOT NULL,
 AlbumId      INT64 NOT NULL,
 AlbumTitle   STRING(MAX),
 ReleaseDate  DATE
) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

Para ver todas as referências do SQL, consulte Sintaxe da instrução, Funções e operadores e Estrutura léxica e sintaxe.

PostgreSQL

CREATE TABLE Singers (
 SingerId   BIGINT PRIMARY KEY,
 FirstName  VARCHAR(1024),
 LastName   VARCHAR(1024),
 SingerInfo BYTEA,
 BirthDate  TIMESTAMPTZ
);

CREATE TABLE Albums (
 SingerId        BIGINT NOT NULL,
 AlbumId         BIGINT NOT NULL,
 AlbumTitle      VARCHAR(1024),
 ReleaseDate     DATE,
 PRIMARY KEY(SingerId, AlbumId),
 FOREIGN KEY (SingerId) REFERENCES Singers(SingerId)
) INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

Para mais informações, consulte A linguagem PostgreSQL no Spanner.

Usar parâmetros de consulta

O Spanner oferece suporte a parâmetros de consulta para aumentar o desempenho e ajudar a evitar a injeção de SQL quando as consultas são construídas usando a entrada do usuário. Os parâmetros de consulta podem ser usados como substitutos de expressões arbitrárias, mas não como substitutos de identificadores, nomes de colunas, nomes de tabelas ou outras partes da consulta.

Os parâmetros podem ser exibidos em qualquer lugar onde se espera um valor literal. O mesmo nome de parâmetro pode ser usado mais de uma vez em uma única instrução SQL.

Em resumo, os parâmetros de consulta são compatíveis com a execução de consultas das seguintes maneiras:

  • Planos pré-otimizados: as consultas que usam parâmetros podem ser executadas mais rapidamente em cada invocação porque a parametrização facilita o armazenamento em cache do plano de execução pelo Spanner.
  • Composição de consulta simplificada: não é necessário inserir caracteres de escape em valores de string ao fornecê-los em parâmetros de consulta. Os parâmetros de consulta também reduzem o risco de erros de sintaxe.
  • Segurança: os parâmetros de consulta tornam suas consultas mais seguras, protegendo você de vários ataques de injeção de SQL. Essa proteção é especialmente importante para consultas que você constrói com base na entrada do usuário.

Entender como o Spanner executa consultas

Com o Spanner, é possível consultar bancos de dados usando instruções SQL declarativas que especificam quais dados você quer recuperar. Se você quiser entender como o Spanner recebe os resultados, examine o plano de execução da consulta. Um plano de execução de consulta exibe o custo computacional associado a cada etapa da consulta. Usando os custos, é possível depurar os problemas de desempenho da consulta e otimizá-la. Para saber mais, consulte Planos de execução de consulta.

Recupere planos de execução de consulta por meio do console do Google Cloud ou com as bibliotecas de cliente.

Para receber um plano de execução de consulta para uma consulta específica usando o console do Google Cloud, siga estas etapas:

  1. Abra a página "Instâncias do Spanner".

    Acessar "Instâncias do Spanner"

  2. Selecione os nomes da instância do Spanner e o banco de dados que você quer consultar.

  3. Clique em Spanner Studio no painel de navegação à esquerda.

  4. Digite a consulta no campo de texto e clique em Executar consulta.

  5. Clique em Explicação
    . O console do Google Cloud exibe um plano de execução visual para sua consulta.

    Captura de tela do plano de execução visual no console do Cloud

Para mais informações sobre como entender os planos visuais e usá-los para depurar consultas, consulte Ajustar uma consulta usando o visualizador de planos de consulta.

Você também pode ver amostras de planos de consulta históricos e comparar o desempenho de uma consulta ao longo do tempo em relação a determinadas consultas. Para saber mais, acesse Planos de consulta de amostra.

Usar índices secundários

Assim como outros bancos de dados relacionais, o Spanner oferece índices secundários, que podem ser usados para recuperar dados usando uma instrução SQL ou a interface de leitura do Spanner. A maneira mais comum de buscar dados de um índice é usar o Spanner Studio. Usar um índice secundário em uma consulta SQL permite especificar como você quer que o Spanner receba os resultados. A especificação de um índice secundário pode acelerar a execução da consulta.

Por exemplo, suponha que você queira buscar os IDs de todos os cantores com um sobrenome específico. Uma maneira de escrever uma consulta SQL é:

SELECT s.SingerId
FROM Singers AS s
WHERE s.LastName = 'Smith';

Essa consulta retornaria os resultados que você espera, mas talvez levasse muito tempo para fazer isso. O tempo dependerá do número de linhas na tabela Singers e quantas satisfazem o predicado WHERE s.LastName = 'Smith'. Se não houver um índice secundário que contenha a coluna LastName a ser lida, o plano de consulta vai ler toda a tabela Singers para encontrar linhas que correspondam ao predicado. Ler a tabela inteira é chamado de verificação completa da tabela. Uma verificação completa da tabela é uma maneira cara de conseguir os resultados quando a tabela contém apenas uma pequena porcentagem de Singers com esse sobrenome.

É possível melhorar o desempenho dessa consulta definindo um índice secundário na coluna de sobrenome:

CREATE INDEX SingersByLastName ON Singers (LastName);

Como o índice secundário SingersByLastName contém a coluna da tabela indexada LastName e a coluna de chave primária SingerId, o Spanner pode buscar todos os dados da tabela de índices muito menor em vez de verificar toda a tabela Singers.

Nesse cenário, o Spanner usa automaticamente o índice secundário SingersByLastName ao executar a consulta, desde que tenham se passado três dias desde a criação do banco de dados. Consulte Uma observação sobre novos bancos de dados. No entanto, é melhor dizer explicitamente ao Spanner para usar esse índice, especificando uma diretiva de índice na cláusula FROM:

GoogleSQL

SELECT s.SingerId
FROM Singers@{FORCE_INDEX=SingersByLastName} AS s
WHERE s.LastName = 'Smith';

PostgreSQL

 SELECT s.SingerId
FROM Singers /*@ FORCE_INDEX=SingersByLastName */ AS s
WHERE s.LastName = 'Smith';

Agora, suponha que você também queira buscar o nome do cantor, além do ID. Mesmo que a coluna FirstName não esteja contida no índice, você ainda precisa especificar a diretiva de índice como antes:

GoogleSQL

SELECT s.SingerId, s.FirstName
FROM Singers@{FORCE_INDEX=SingersByLastName} AS s
WHERE s.LastName = 'Smith';

PostgreSQL

SELECT s.SingerId, s.FirstName
FROM Singers /*@ FORCE_INDEX=SingersByLastName */ AS s
WHERE s.LastName = 'Smith';

Você ainda recebe um benefício de desempenho ao usar o índice porque o Spanner não precisa fazer uma verificação completa da tabela ao executar o plano de consulta. Em vez disso, ele seleciona o subconjunto de linhas que satisfazem o predicado do índice SingersByLastName e, em seguida, faz uma pesquisa na tabela base Singers para buscar o primeiro nome apenas desse subconjunto de linhas.

Se você quiser que o Spanner não precise buscar nenhuma linha da tabela base, armazene uma cópia da coluna FirstName no próprio índice:

GoogleSQL

CREATE INDEX SingersByLastName ON Singers (LastName) STORING (FirstName);

PostgreSQL

CREATE INDEX SingersByLastName ON Singers (LastName) INCLUDE (FirstName);

Usar uma cláusula STORING (para o dialeto GoogleSQL) ou uma cláusula INCLUDE (para o dialeto PostgreSQL), como isso, custa armazenamento extra, mas oferece as seguintes vantagens:

  • As consultas SQL que usam o índice e selecionam colunas armazenadas na cláusula STORING ou INCLUDE não exigem uma junção extra à tabela base.
  • As chamadas de leitura que usam o índice podem ler colunas armazenadas na cláusula STORING ou INCLUDE.

Os exemplos anteriores ilustram como índices secundários podem agilizar consultas quando as linhas escolhidas pela cláusula WHERE podem ser identificadas rapidamente usando o índice secundário.

Outro cenário em que índices secundários podem oferecer benefícios de desempenho é para determinadas consultas que retornam resultados ordenados. Por exemplo, suponha que você queira buscar todos os títulos de álbuns e as datas de lançamento em ordem crescente de data de lançamento e ordem decrescente de título do álbum. Você poderia escrever uma consulta SQL da seguinte maneira:

SELECT a.AlbumTitle, a.ReleaseDate
FROM Albums AS a
ORDER BY a.ReleaseDate, a.AlbumTitle DESC;

Sem um índice secundário, esta consulta requer uma etapa de classificação potencialmente cara no plano de execução. É possível agilizar a execução da consulta definindo esse índice secundário:

CREATE INDEX AlbumsByReleaseDateTitleDesc on Albums (ReleaseDate, AlbumTitle DESC);

Em seguida, reescreva a consulta para usar o índice secundário:

GoogleSQL

SELECT a.AlbumTitle, a.ReleaseDate
FROM Albums@{FORCE_INDEX=AlbumsByReleaseDateTitleDesc} AS a
ORDER BY a.ReleaseDate, a.AlbumTitle DESC;

PostgreSQL

SELECT a.AlbumTitle, a.ReleaseDate
FROM Albums /*@ FORCE_INDEX=AlbumsByReleaseDateTitleDesc */ AS s
ORDER BY a.ReleaseDate, a.AlbumTitle DESC;

Esta definição de consulta e de índice atende aos dois critérios a seguir:

  • Para remover a etapa de classificação, verifique se a lista de colunas na cláusula ORDER BY é um prefixo da lista de chaves de índice.
  • Para evitar a mesclagem da tabela base para buscar colunas ausentes, verifique se o índice cubra todas as colunas na tabela que a consulta usa.

Os índices secundários podem acelerar consultas comuns, mas a adição de índices secundários pode adicionar latência às operações de confirmação, porque cada índice secundário normalmente requer o envolvimento de um nó extra em cada confirmação. Na maioria das cargas de trabalho, não há problemas em ter alguns índices secundários. No entanto, você precisa considerar se é mais importante a latência de leitura ou de gravação e quais operações são as mais críticas para a carga de trabalho. Compare sua carga de trabalho para garantir que ela esteja funcionando conforme o esperado.

Para a referência completa de índices secundários, consulte Índices secundários.

Otimizar verificações

Algumas consultas do Spanner podem se beneficiar do uso de um método de processamento orientado em lote ao verificar dados em vez do método mais comum de processamento orientado por linhas. O processamento de verificações em lotes é uma maneira mais eficiente de processar grandes volumes de dados de uma só vez e permite que as consultas alcancem menor utilização de CPU e latência.

A operação de verificação do Spanner sempre inicia a execução no modo orientado a linhas. Durante esse período, o Spanner coleta várias métricas de ambiente de execução. Em seguida, o Spanner aplica um conjunto de heurística com base no resultado dessas métricas para determinar o modo de verificação ideal. Quando apropriado, o Spanner alterna para um modo de processamento orientado em lote para ajudar a melhorar a capacidade e o desempenho da verificação.

Casos de uso comuns

As consultas com as seguintes características geralmente se beneficiam do uso do processamento orientado em lote:

  • Grandes verificações de dados atualizados com pouca frequência.
  • Verificações com predicados em colunas de largura fixa.
  • Verificações com grandes contagens de busca. (Uma busca usa um índice para recuperar registros.)

Casos de uso sem ganhos de desempenho

Nem todas as consultas se beneficiam do processamento orientado em lote. Os seguintes tipos de consulta têm um desempenho melhor com o processamento de verificação orientado por linhas:

  • Consultas de pesquisa de ponto: consultas que buscam apenas uma linha.
  • Consultas de verificação pequena: verificações de tabela que verificam apenas algumas linhas, a menos que tenham grandes contagens de busca.
  • Consultas que usam LIMIT.
  • Consultas que leem dados de alta desistência de usuários: consultas em que mais de 10% da leitura de dados é atualizada com frequência.
  • Consultas com linhas que contêm valores grandes: linhas de valores grandes são aquelas que contêm valores maiores que 32.000 bytes (pré-compactação) em uma única coluna.

Como verificar o método de verificação usado por uma consulta

Para verificar se a consulta usa processamento orientado em lote, por linha ou se está alternando automaticamente entre os dois métodos de verificação:

  1. Acesse a página Instâncias do Spanner no console do Google Cloud.

    Acessar a página "Instâncias"

  2. Clique no nome da instância com a consulta que você quer investigar.

  3. Na tabela "Bancos de dados", clique no banco de dados com a consulta que você quer investigar.

  4. No menu de navegação, clique em Spanner Studio.

  5. Abra uma nova guia clicando em Nova guia do editor SQL ou Nova guia.

  6. Quando o editor de consultas aparecer, crie sua consulta.

  7. Clique em Run.

    O Spanner executa a consulta e mostra os resultados.

  8. Clique na guia Explicação abaixo do editor de consultas.

    O Spanner mostra um visualizador de plano de execução de plano de consulta. Cada cartão no gráfico representa um iterador.

  9. Clique no card do iterador Table scan para abrir um painel de informações.

    O painel de informações mostra dados contextuais sobre a verificação selecionada. O método de leitura é mostrado neste card. Automático: indica que o Spanner determina o método de verificação. Outros valores possíveis incluem Vectorized para o processamento orientado em lote e com Scalar para o processamento orientado por linhas.

    Captura de tela de um card de verificação de tabela mostrando o método de verificação como "Automático"

Como aplicar o método de verificação usado por uma consulta

Para otimizar o desempenho da consulta, o Spanner escolhe o método de verificação ideal para sua consulta. Recomendamos que você use esse método de verificação padrão. No entanto, pode haver cenários em que você queira aplicar um tipo específico de método de verificação.

Como aplicar a verificação orientada em lote

É possível aplicar a verificação orientada por lote no nível da tabela e da instrução.

Para aplicar o método de verificação orientada em lote no nível da tabela, use uma dica de tabela na consulta:

GoogleSQL

  SELECT ...
  FROM (t1@{SCAN_METHOD=BATCH} JOIN t2 ON ...)
  WHERE ...

PostgreSQL

  SELECT ...
  FROM (t1/*@ scan_method=batch */ JOIN t2 on ...)
  WHERE ...

Para aplicar o método de verificação orientada em lote no nível da instrução, use uma dica de instrução na consulta:

GoogleSQL

  @{SCAN_METHOD=BATCH}
  SELECT ...
  FROM ...
  WHERE ...

PostgreSQL

  /*@ scan_method=batch */
  SELECT ...
  FROM ...
  WHERE ...

Como desativar a verificação automática e aplicar a verificação orientada a linhas

Embora não seja recomendado desativar o método de verificação automático definido pelo Spanner, é possível desativá-lo e usar o método de verificação orientado por linha para fins de solução de problemas, como diagnóstico de latência.

Para desativar o método de verificação automática e aplicar o processamento de linhas no nível da tabela, use uma dica de tabela na consulta:

GoogleSQL

  SELECT ...
  FROM (t1@{SCAN_METHOD=ROW} JOIN t2 ON ...)
  WHERE ...

PostgreSQL

  SELECT ...
  FROM (t1/*@ scan_method=row */ JOIN t2 on ...)
  WHERE ...

Para desativar o método de verificação automática e aplicar o processamento de linhas no nível da instrução, use uma dica de instrução na consulta:

GoogleSQL

  @{SCAN_METHOD=ROW}
  SELECT ...
  FROM ...
  WHERE ...

PostgreSQL

  /*@ scan_method=row */
  SELECT ...
  FROM ...
  WHERE ...

Otimizar pesquisas de chave de intervalo

Um uso comum de uma consulta SQL é ler várias linhas do Spanner com base em uma lista de chaves conhecidas.

As práticas recomendadas a seguir ajudam a escrever consultas eficientes durante a busca de dados por um intervalo de chaves:

  • Se a lista de chaves for esparsa e não adjacente, use parâmetros de consulta e UNNEST para construir a consulta.

    Por exemplo, se a lista de chaves for {1, 5, 1000}, escreva a consulta assim:

    GoogleSQL

    SELECT *
    FROM Table AS t
    WHERE t.Key IN UNNEST (@KeyList)
    

    PostgreSQL

    SELECT *
    FROM Table AS t
    WHERE t.Key IN UNNEST ($1)
    

    Observações:

    • O operador UNNEST da matriz nivela uma matriz de entrada em linhas de elementos.

    • O parâmetro de consulta, que é @KeyList para GoogleSQL e $1 para PostgreSQL, pode acelerar sua consulta conforme discutido na prática recomendada anterior.

  • Se a lista de chaves for adjacente e estiver dentro de um intervalo, especifique os limites mínimo e mais alto do intervalo de chaves na cláusula WHERE.

    Por exemplo, se a lista de chaves for {1,2,3,4,5}, crie a consulta desta maneira:

    GoogleSQL

    SELECT *
    FROM Table AS t
    WHERE t.Key BETWEEN @min AND @max
    

    PostgreSQL

    SELECT *
    FROM Table AS t
    WHERE t.Key BETWEEN $1 AND $2
    

    Essa consulta só é mais eficiente se as chaves no intervalo de chaves forem adjacentes. Em outras palavras, se a lista de chaves for {1, 5, 1000}, não especifique os limites inferior e superior, como na consulta anterior, porque a consulta resultante verificaria todos os valores entre 1 e 1.000.

Otimizar mesclagens

As operações de mesclagem podem ser caras, porque podem aumentar significativamente o número de linhas que a consulta precisa verificar, o que resulta em consultas mais lentas. Além das técnicas que você está acostumado a usar em outros bancos de dados relacionais para otimizar as consultas de mesclagem, aqui estão algumas práticas recomendadas para uma JOIN mais eficiente ao usar o SQL do Spanner:

  • Se possível, vincule dados em tabelas intercaladas por chave principal. Exemplo:

    SELECT s.FirstName, a.ReleaseDate
    FROM Singers AS s JOIN Albums AS a ON s.SingerId = a.SingerId;
    

    As linhas na tabela intercalada Albums têm a garantia de estar fisicamente armazenadas nas mesmas divisões que a linha pai em Singers, conforme discutido no Esquema e Modelo de Dados. Portanto, as mesclagens podem ser concluídas localmente sem enviar muitos dados pela rede.

  • Use a diretiva de junção se você quiser forçar a ordem da junção. Exemplo:

    GoogleSQL

    SELECT *
    FROM Singers AS s JOIN@{FORCE_JOIN_ORDER=TRUE} Albums AS a
    ON s.SingerId = a.Singerid
    WHERE s.LastName LIKE '%x%' AND a.AlbumTitle LIKE '%love%';
    

    PostgreSQL

    SELECT *
    FROM Singers AS s JOIN/*@ FORCE_JOIN_ORDER=TRUE */ Albums AS a
    ON s.SingerId = a.Singerid
    WHERE s.LastName LIKE '%x%' AND a.AlbumTitle LIKE '%love%';
    

    A diretiva de junção FORCE_JOIN_ORDER instrui o Spanner a usar a ordem de junção especificada na consulta (ou seja, Singers JOIN Albums, não Albums JOIN Singers). Os resultados retornados são os mesmos, independentemente da ordem escolhida pelo Spanner. No entanto, é recomendável usar essa diretiva de mesclagem se você perceber no plano de consulta que o Spanner mudou a ordem de mesclagem e causou consequências indesejáveis, como resultados intermediários maiores, ou que perdeu oportunidades de procurar linhas.

  • Use uma diretiva de vinculação para escolher uma implementação de junção. Quando você usa o SQL para consultar várias tabelas, o Spanner usa automaticamente um método de junção que provavelmente torna a consulta mais eficiente. No entanto, o Google aconselha realizar testes com diferentes algoritmos de mesclagem. Escolher o algoritmo de mesclagem certo para a consulta pode melhorar a latência, o consumo de memória ou ambos. Esta consulta demonstra a sintaxe para usar uma diretiva JOIN com a dica JOIN_METHOD para escolher um HASH JOIN:

    GoogleSQL

    SELECT *
    FROM Singers s JOIN@{JOIN_METHOD=HASH_JOIN} Albums AS a
    ON a.SingerId = a.SingerId
    

    PostgreSQL

    SELECT *
    FROM Singers s JOIN/*@ JOIN_METHOD=HASH_JOIN */ Albums AS a
    ON a.SingerId = a.SingerId
    
  • Se você estiver usando HASH JOIN ou APPLY JOIN e tiver uma cláusula WHERE altamente seletiva em um lado da JOIN, coloque a tabela que produz o menor número de linhas como a primeira tabela na cláusula FROM da junção. Essa estrutura ajuda porque, atualmente em HASH JOIN, o Spanner sempre escolhe a tabela do lado esquerdo como criação e a tabela do lado direito como sondagem. Da mesma forma, para APPLY JOIN, o Spanner escolhe a tabela do lado esquerdo como externa e a tabela do lado direito como interna. Saiba mais sobre esses tipos de mesclagem: Hash e Apply.

  • Para consultas que são essenciais para a carga de trabalho, especifique o método de mesclagem com melhor desempenho e a ordem de mesclagem nas instruções SQL para um desempenho mais consistente.

Evitar grandes leituras em transações de leitura e gravação

Transações de leitura/gravação permitem uma sequência de zero ou mais leituras ou consultas SQL e podem incluir um conjunto de mutações, antes de uma chamada para confirmação. Para manter a consistência dos dados, o Spanner adquire bloqueios ao ler e gravar linhas nas tabelas e nos índices. Para mais informações sobre bloqueio, consulte Vida de leituras e gravações.

Devido à maneira como o bloqueio funciona no Spanner, realizar uma consulta de leitura ou SQL que leia um grande número de linhas (por exemplo, SELECT * FROM Singers) significa que nenhuma outra transação pode gravar nas linhas que você leu até que a transação seja confirmada ou cancelada.

Além disso, como sua transação está processando um grande número de linhas, é provável que demore mais do que uma transação que lê um intervalo muito menor de linhas (por exemplo, SELECT LastName FROM Singers WHERE SingerId = 7), o que agrava ainda mais o problema e reduz a capacidade do sistema.

Por isso, tente evitar leituras grandes (por exemplo, verificações de tabela completas ou operações de mesclagem massiva) em suas transações, a menos que você esteja disposto a aceitar menor capacidade de gravação.

Em alguns casos, o seguinte padrão pode gerar melhores resultados:

  1. Faça suas leituras grandes dentro de uma transação somente leitura. As transações somente leitura permitem maior capacidade agregada porque não usam bloqueios.
  2. Opcional: faça o processamento necessário nos dados que você acabou de ler.
  3. Inicie uma transação de leitura/gravação.
  4. Verifique se as linhas críticas não mudaram os valores desde que você executou a transação somente leitura na etapa 1.
    • Se houve mudança, reverta sua transação e comece novamente na etapa 1.
    • Se tudo estiver certo, confirme as mutações.

Uma maneira de garantir que você esteja evitando leituras grandes em transações de leitura/gravação é analisar os planos de execução gerados pelas consultas.

Usar ORDER BY para garantir a ordem dos resultados SQL

Se você espera uma certa ordem para os resultados de uma consulta SELECT, inclua explicitamente a cláusula ORDER BY. Por exemplo, se você quiser listar todos os cantores em ordem de chave primária, use esta consulta:

SELECT * FROM Singers
ORDER BY SingerId;

O Spanner garante a ordenação de resultados apenas se a cláusula ORDER BY estiver presente na consulta. Em outras palavras, considere esta consulta sem o ORDER BY:

SELECT * FROM Singers;

O Spanner não garante que os resultados dessa consulta estejam em ordem de chave primária. Além disso, a ordem dos resultados pode mudar a qualquer momento e não há garantia de consistência de invocação para invocação. Se uma consulta tiver uma cláusula ORDER BY e o Spanner usar um índice que fornece a ordem necessária, o Spanner não classificará os dados explicitamente. Portanto, não se preocupe com o impacto no desempenho da inclusão dessa cláusula. Para verificar se uma operação de classificação explícita está incluída na execução, consulte o plano de consulta.

Usar STARTS_WITH em vez de LIKE

Como o Spanner não avalia padrões LIKE parametrizados até o momento da execução, ele precisa ler todas as linhas e avaliá-las na expressão LIKE para filtrar as que não forem correspondentes.

Quando um padrão LIKE tiver o formato foo% (por exemplo, começar com uma string fixa e terminar com uma única porcentagem de caractere curinga) e a coluna for indexada, use STARTS_WITH em vez de LIKE. Essa opção permite que o Spanner otimize com mais eficiência o plano de execução da consulta.

Não recomendado:

GoogleSQL

SELECT a.AlbumTitle FROM Albums a
WHERE a.AlbumTitle LIKE @like_clause;

PostgreSQL

SELECT a.AlbumTitle FROM Albums a
WHERE a.AlbumTitle LIKE $1;

Recomendado:

GoogleSQL

SELECT a.AlbumTitle FROM Albums a
WHERE STARTS_WITH(a.AlbumTitle, @prefix);

PostgreSQL

SELECT a.AlbumTitle FROM Albums a
WHERE STARTS_WITH(a.AlbumTitle, $2);

Usar carimbos de data/hora de confirmação

Se o aplicativo precisar consultar dados gravados após um determinado momento, adicione colunas de carimbo de data/hora de confirmação às tabelas relevantes. Os carimbos de data/hora de confirmação permitem uma otimização do Spanner que pode reduzir a E/S de consultas com cláusulas WHERE que restringem os resultados às linhas gravadas mais recentemente do que um horário específico.

Saiba mais sobre essa otimização com bancos de dados de dialetos GoogleSQL ou com bancos de dados PostgreSQL-dialect.