Práticas recomendadas de Linguagem de manipulação de dados

Nesta página, descrevemos as práticas recomendadas para o uso da linguagem de manipulação de dados (DML, na sigla em inglês) e da DML particionada.

Use uma cláusula WHERE para reduzir o escopo dos bloqueios

As instruções DML são executadas dentro de transações de leitura e gravação. Quando o Spanner lê dados, ele adquire bloqueios de leitura compartilhados em partes limitadas dos intervalos de linhas que você lê. Especificamente, ele adquire esses bloqueios apenas nas colunas acessadas. Os bloqueios podem incluir dados que não atendem à condição de filtro da cláusula WHERE.

Quando o Spanner modifica dados usando instruções DML, ele adquire bloqueios exclusivos nos dados específicos que você está modificando. Além disso, ele adquire bloqueios compartilhados da mesma maneira que quando você lê dados. Se a solicitação incluir intervalos de linhas grandes ou uma tabela inteira, os bloqueios compartilhados poderão impedir que outras transações progridam em paralelo.

Para modificar os dados da maneira mais eficiente possível, use uma cláusula WHERE que permita que o Spanner leia apenas as linhas necessárias. É possível atingir essa meta com um filtro na chave principal ou na chave de um índice secundário. A cláusula WHERE limita o escopo dos bloqueios compartilhados e permite que o Spanner processe a atualização com mais eficiência.

Por exemplo, suponha que um dos músicos da tabela Singers altere seu nome e você precise atualizar essa informação no banco de dados. É possível executar a instrução DML a seguir, mas ela força o Spanner a verificar a tabela inteira e adquire bloqueios compartilhados que cobrem a tabela inteira. Como resultado, o Spanner precisa ler mais dados do que o necessário, e transações simultâneas não podem modificar os dados em paralelo:

-- ANTI-PATTERN: SENDING AN UPDATE WITHOUT THE PRIMARY KEY COLUMN
-- IN THE WHERE CLAUSE

UPDATE Singers SET FirstName = "Marcel"
WHERE FirstName = "Marc" AND LastName = "Richards";

Para tornar a atualização mais eficiente, inclua a coluna SingerId na cláusula WHERE. A coluna SingerId é a única coluna de chave primária da tabela Singers:

-- ANTI-PATTERN: SENDING AN UPDATE THAT MUST SCAN THE ENTIRE TABLE

UPDATE Singers SET FirstName = "Marcel"
WHERE FirstName = "Marc" AND LastName = "Richards"

Se não houver índice em FirstName ou LastName, você precisará verificar a tabela inteira para encontrar os cantores de destino. Se você não quiser adicionar um índice secundário para tornar a atualização mais eficiente, inclua a coluna SingerId na cláusula WHERE.

A coluna SingerId é a única coluna de chave primária da tabela Singers. Para encontrá-lo, execute SELECT em uma transação separada somente leitura antes da transação de atualização:


  SELECT SingerId
  FROM Singers
  WHERE FirstName = "Marc" AND LastName = "Richards"

  -- Recommended: Including a seekable filter in the where clause

  UPDATE Singers SET FirstName = "Marcel"
  WHERE SingerId = 1;

Evitar o uso de instruções DML e mutações na mesma transação

O Spanner armazena em buffer inserções, atualizações e exclusões realizadas usando instruções DML no lado do servidor, e os resultados são visíveis para instruções SQL e DML subsequentes na mesma transação. Esse comportamento é diferente da API Mutation, em que o Spanner armazena em buffer as mutações no lado do cliente e as envia para o lado do servidor como parte da operação de confirmação. Como resultado, as mutações na solicitação de confirmação não são visíveis para as instruções SQL ou DML na mesma transação.

Evite usar instruções DML e mutações na mesma transação. Se você usar os dois na mesma transação, precisará considerar a ordem de execução no código da biblioteca de cliente. Se uma transação contiver instruções DML e mutações na mesma solicitação, o Spanner executará as instruções DML antes das mutações.

Para operações compatíveis apenas com mutações, convém combinar instruções DML e mutações na mesma transação, por exemplo, insert_or_update.

Se você usar ambos, o buffer gravará somente no final da transação.

Use a função PENDING_COMMIT_TIMESTAMP para gravar carimbos de data/hora de confirmação

GoogleSQL

Use a função PENDING_COMMIT_TIMESTAMP para gravar o carimbo de data/hora de confirmação em uma instrução DML. O Spanner seleciona o carimbo de data/hora de confirmação quando a transação é confirmada.

PostgreSQL

Use a função SPANNER.PENDING_COMMIT_TIMESTAMP() para gravar o carimbo de data/hora de confirmação em uma instrução DML. O Spanner seleciona o carimbo de data/hora de confirmação quando a transação é confirmada.

DML particionada e funções date e timestamp

A DML particionada usa uma ou mais transações que podem ser executadas e confirmadas em momentos diferentes. Se você usar as funções date ou timestamp, as linhas modificadas poderão conter valores diferentes.

Melhorar a latência com DML em lote

Para reduzir a latência, use a DML em lote para enviar várias instruções DML ao Spanner em uma única viagem de ida e volta de cliente-servidor.

A DML em lote pode aplicar otimizações a grupos de instruções em um lote para permitir atualizações de dados mais rápidas e eficientes.

  • Executar gravações com uma única solicitação

    O Spanner otimiza automaticamente grupos contíguos de instruções em lote INSERT, UPDATE ou DELETE semelhantes que têm valores de parâmetro diferentes, se eles não violarem as dependências de dados.

    Por exemplo, considere um cenário em que você quer inserir um grande conjunto de novas linhas em uma tabela chamada Albums. Para permitir que o Spanner otimize todas as instruções INSERT necessárias em uma única ação eficiente do lado do servidor, comece escrevendo uma instrução DML apropriada que use parâmetros de consulta SQL:

    INSERT INTO Albums (SingerId, AlbumId, AlbumTitle) VALUES (@Singer, @Album, @Title);
    

    Em seguida, envie ao Spanner um lote de DML que invoque essa instrução repetidamente e de maneira contígua, com as repetições diferentes apenas nos valores vinculados aos três parâmetros de consulta da instrução. O Spanner otimiza essas instruções DML estruturalmente idênticas em uma única operação do lado do servidor antes de executá-la.

  • Executar gravações em paralelo

    O Spanner otimiza automaticamente grupos contíguos de instruções DML executando em paralelo quando isso não violaria as dependências de dados. Essa otimização traz benefícios de desempenho para um conjunto mais amplo de instruções DML em lote, porque pode ser aplicada a uma combinação de tipos de instrução DML (INSERT, UPDATE e DELETE) e a instruções DML parametrizadas ou não parametrizadas.

    Por exemplo, o esquema de amostra tem as tabelas Singers, Albums e Accounts. Albums é intercalado em Singers e armazena informações sobre álbuns para Singers. O grupo contíguo de instruções a seguir grava novas linhas em várias tabelas e não tem dependências de dados complexas.

    INSERT INTO Singers (SingerId, Name) VALUES(1, "John Doe");
    INSERT INTO Singers (SingerId, Name) VALUES(2, "Marcel Richards");
    INSERT INTO Albums(SingerId, AlbumId, AlbumTitle) VALUES (1, 10001, "Album 1");
    INSERT INTO Albums(SingerId, AlbumId, AlbumTitle) VALUES (1, 10002, "Album 2");
    INSERT INTO Albums(SingerId, AlbumId, AlbumTitle) VALUES (2, 10001, "Album 1");
    UPDATE Accounts SET Balance = 100 WHERE AccountId = @AccountId;
    

    O Spanner otimiza esse grupo de instruções DML executando-as em paralelo. As gravações são aplicadas na ordem das instruções no lote e mantêm a semântica DML em lote se uma instrução falhar durante a execução.