Consulta SQL++ / N1QL

Teste de ANSI JOINs

Visão geral

O principal objetivo deste artigo é mostrar como os ANSI JOINs do Couchbase são testados. Em Couchbase versão 5.5Agora, você pode executar uniões usando a sintaxe padrão ANSI. Esse acréscimo às uniões as torna muito mais flexíveis, mas também muito mais complexas. Essa complexidade dificulta o teste em nossa estrutura normal, pois há possibilidades demais para serem escritas manualmente para automação. Felizmente, uma de nossas estruturas de teste nos permite definir os parâmetros de uma consulta e, em seguida, gerar conjuntos aleatórios de consultas com base nesses parâmetros. Essa estrutura é conhecida como Gerador de consultas aleatórias (RQG). Neste artigo, discutiremos como o RQG é usado para testar a funcionalidade ANSI JOIN que foi implementada. Primeiro, vamos dar uma breve olhada no que há de diferente nos ANSI JOINs.

Neste artigo, abordaremos os seguintes tópicos:

1. Introdução aos ANSI JOINs

2. Visão geral do gerador de consultas aleatórias (RQG)

3. USANDO o RQG para testar ANSI JOINs

4. Pontos principais

5. Lista de bugs adicionais do ANSI JOIN encontrados

6. Apêndice

Introdução aos ANSI JOINs

Anteriormente, no Couchbase, você só podia executar uniões de pesquisa e uniões de índices. Isso era bom para consultas em que um lado da união pode produzir uma chave de documento do outro lado da união. No entanto, o problema com isso é que as uniões não podiam ser executadas em outros campos de um espaço-chave. As uniões ANSI corrigem esse problema e vão além: agora as uniões podem ser executadas em campos arbitrários ou expressões que resultam em campos, ou em várias condições de união.

Sintaxe antiga do Join:

        Lhs-keyspace [join-type] JOIN rhs-keyspace

ON KEYS [expressão que resulta em um meta().id de um dos espaços-chave]

Sintaxe ANSI JOIN:

lhs-expression [join-type] JOIN rhs-keyspace ON [join-condition]

Consulta de sintaxe de junção antiga:

Mesma consulta com ANSI JOINs Sintaxe:

Os tipos de junção compatíveis com o N1QL são INNER JOIN ou LEFT/RIGHT OUTER JOIN. Se você simplesmente colocar JOIN, isso será interpretado como INNER JOIN, e LEFT/RIGHT JOIN será interpretado como OUTER JOIN. Na nova sintaxe de união, o lado esquerdo da união pode ser um espaço-chave, uma consulta n1ql aninhada, uma expressão n1ql ou a própria união. O lado direito da união deve ser um espaço de chave na implementação atual de ANSI JOINs dentro do Couchbase. A cláusula ON contém as condições que a união deve atender. Essas condições podem ser qualquer expressão de predicado, desde que haja um índice adequado no espaço de chave do lado direito. Portanto, você pode fazer comparações de igualdade e comparações de não igualdade (b1.field = b2.field ou b1.field/=/!=/b2.field ou b2.field is NOT NULL ou expressão complexa = b2.field). Esta é uma breve análise do novo recurso. Para se aprofundar no recurso, consulte esta postagem do blog escrita por Bingjie Miao (o desenvolvedor que implementou o recurso): https://www.couchbase.com/blog/ansi-join-support-n1ql/

Agora começamos a entender que as ANSI JOINs têm pouquíssimas limitações em comparação com nossas antigas junções. O lado esquerdo de uma união ANSI pode ser muito complexo, podendo até ser várias uniões, ou uma consulta aninhada que resulta em alguns dados json, ou várias consultas aninhadas. Devido a esse nível de complexidade, é melhor usar algo que chamamos de RQG, em vez de criar consultas individuais para testar. Aqui está uma breve visão geral de como o RQG funciona.

Visão geral do gerador de consultas aleatórias (RQG)

O RQG é uma estrutura que foi escrita pelo Couchbase e que aproveita outra estrutura chamada Randgen. Basicamente, especificamos um conjunto de parâmetros em um arquivo chamado gramática e, a partir desses parâmetros, o Randgen criará modelos de consulta SQL (consultas com espaços reservados para os nomes de campo e de tabela) e, em seguida, nossa estrutura processa esses modelos e os converte em consultas formatadas em N1QL com base no conjunto de dados carregado no couchbase.

Exemplo de modelo de consulta:

Esse modelo é gerado a partir do arquivo de gramática que contém os parâmetros. Basicamente, o arquivo de gramática informa ao randgen para gerar uma consulta que seleciona uma lista de dados de tipo numérico de uma união de dois compartimentos arbitrários em uma comparação de igualdade. A gramática terá vários tipos de campos a serem selecionados e várias condições de união que podem ser inseridas nos predicados ON/ WHERE. Depois que o modelo for gerado, conforme mostrado acima, nossa estrutura irá substituir esses valores arbitrários por valores baseados nos dados carregados. Para NUMERIC_FIELD_LIST, ele selecionará um campo que seja uma lista de ints/bigints/floats/decimals/etc, dependendo do que estiver disponível. A estrutura substituirá BUCKET_NAME pelo nome específico de um bucket existente no servidor. PREVIOUS_TABLE.FIELD será um campo do primeiro bucket e CURRENT_TABLE.FIELD será o mesmo campo do segundo bucket. Depois que tudo isso for feito, ele analisará a consulta e criará uma cópia da consulta, na qual todas as diferenças entre o N1QL e o SQL serão eliminadas. Por exemplo, na antiga sintaxe de junção, não podíamos usar a palavra-chave ON, então, em vez disso, o RQG converteria ON em ON KEYS para as consultas n1ql.

Exemplo de consulta convertida:

Em seguida, tanto as consultas n1ql quanto as consultas sql são executadas no servidor couchbase e em um servidor MySQL equivalente. Os resultados das consultas N1QL são comparados com os resultados das consultas MySQL equivalentes. Nosso objetivo é fazer com que nossos resultados correspondam aos resultados do MySQL, pois queremos que o N1QL seja funcionalmente semelhante ao SQL. Se você quiser saber mais sobre como o RQG é organizado ou como ele gera modelos e os converte em n1ql, consulte esta série de 5 partes sobre o RQG: https://dzone.com/articles/testing-n1ql-sql-for-json

USANDO o RQG para testar ANSI JOINs

A maneira como o RQG é configurado nos permite gerar uma variedade de consultas que, de outra forma, talvez não tivéssemos pensado. Aqui está um modelo extremamente complicado gerado pelo RQG:

Como você pode ver pelo tamanho dessa consulta, teria sido muito difícil criá-la por conta própria, e muitas consultas desse tipo são geradas e executadas por meio do RQG. Essa capacidade de criar consultas altamente complexas o torna perfeitamente adequado para lidar com a complexidade arbitrária dos ANSI JOINs. A gramática que definimos para testar ANSI JOINs tenta capturar a complexidade do lado esquerdo de uma junção, bem como a complexidade da cláusula ON. Dizemos ao RQG para gerar a cláusula lado esquerdo de uma união como uma de três coisas: um espaço-chave normal, uma subconsulta n1ql ou várias uniões aninhadas. Dizemos ao RQG para gerar o lado direito de uma união como um espaço-chave. Em seguida, dizemos ao RQG para gerar o Cláusula ON de uma junção como predicados de igualdade entre dois campos, um do espaço-chave à esquerda ou alias à esquerdae um do espaço de teclas do lado direito. As outras coisas que podem ser geradas na cláusula ON podem ser comparações de não igualdade (/=/!=) ou simplesmente verificar os atributos do campo do espaço-chave à direita (b2.field não é nulo, b2.field não está ausente, b2.field está em uma lista etc.). Para ANSI JOINs, há uma pequena diferença entre o n1ql e o sql. Essa diferença é que o N1QL oferece suporte à comparação IS (NOT) MISSING, o que se deve ao modelo de dados não relacional. Alguns compartimentos podem ter documentos que possuem um campo que outros documentos nesse compartimento não possuem. Portanto, IS (NOT) MISSING significa que o campo não aparece no documento (ou, no caso de IS NOT MISSING, significa que o campo aparece no documento). Tecnicamente, se quiséssemos, também poderíamos dizer ao RQG para gerar subconsultas n1ql dentro da cláusula ON e compará-las com os valores do espaço-chave à direita; no entanto, isso aumentaria exponencialmente o tempo de execução de nossas consultas e não é um caso de uso comum. Aqui estão alguns exemplos de consultas ANSI JOIN geradas a partir do nosso conjunto de parâmetros acima:

Como você pode ver nesses exemplos, a cláusula ON pode ser vários predicados encadeados, encadeados por AND/OR. Também podemos observar que várias junções podem ser executadas em uma consulta e que cada junção pode ter sua própria cláusula ON.

Agora que já entendemos como o RQG gera os modelos e como são esses modelos, vamos dar uma olhada em um exemplo de bug que encontramos na funcionalidade ANSI JOIN e que provavelmente não teríamos encontrado de outra forma. MB-27483, Nesse bug, tivemos a seguinte consulta:

Essa consulta deveria ter sido executada com êxito, dada a forma como o nosso servidor estava configurado; no entanto, em vez de ser executada, ela estava gerando um erro de que o índice adequado não existia no espaço de chave do lado direito. O problema aqui era que a cláusula WHERE estava interferindo na seleção do índice da cláusula ON, fazendo com que a consulta pensasse que não tinha o índice de que precisava, quando esse índice de fato existia. Se analisarmos a cláusula WHERE, veremos que ela é muito complexa, e esse não é o nível de complexidade que normalmente teríamos no lado funcional do teste. Portanto, não teríamos detectado esse bug sem usar o RQG.

Pontos principais

Os ANSI JOINs são bastante flexíveis em termos do que é possível unir, você pode unir expressões arbitrárias com espaços-chave e a cláusula ON pode conter predicados que comparam expressões arbitrárias a campos. Esse nível de complexidade torna impraticável tentar criar consultas específicas para testar cada cenário por conta própria por meio de testes funcionais. Felizmente, temos uma estrutura chamada RQG que é capaz de gerar consultas com base em um conjunto de regras que podemos definir. Essa funcionalidade é muito poderosa e nos permitiu testar ANSI JOINs de forma satisfatória. Por exemplo, se um grande número de consultas complexas estivesse sendo executado, os resultados do ANSI JOIN teriam um desvio de 1. No entanto, se qualquer uma dessas consultas individuais fosse executada isoladamente, os resultados estariam corretos. É por isso que estamos confiantes de que os ANSI JOINs estão em boa forma e prontos para serem usados pelos clientes.

Lista de bugs adicionais do ANSI JOIN encontrados com o RQG:

Número do bug Descrição do bug
MB-27834 Essa consulta não estava usando corretamente a dica de consulta LIMIT; ela executava a consulta inteira antes de aplicar o LIMIT
MB-27763 Essa consulta não estava usando corretamente a dica de consulta LIMIT, semelhante ao bug acima
MB-27483 A consulta pensou que o índice apropriado não existia, o que levou a consulta a lançar um erro. No entanto, o índice estava de fato presente no sistema
MB-27230 O erro errado estava sendo retornado pela consulta
MB-27201 Essa consulta estava apresentando um erro, pois o backfill não estava funcionando corretamente
MB-27109 Outra consulta que achava que o índice de que precisava não estava disponível, embora o índice estivesse presente no sistema
MB-27028 Quando várias consultas foram executadas em sucessão, alguns dos resultados das consultas estavam errados em 1. Quando as consultas foram executadas sozinhas, todos os resultados estavam corretos.
MB-26649 A consulta ficava suspensa de forma intermitente

Apêndice

  1. Blog do Couchbase Server 5.5 GA https://www.couchbase.com/blog/announcing-couchbase-server-5-5/
  2. Uniões de índices https://dzone.com/articles/join-faster-with-couchbase-index-joins
  3. ANSI JOINs Blog do Couchbase https://www.couchbase.com/blog/ansi-join-support-n1ql/
  4. Randgen https://launchpad.net/randgen
  5. Série de artigos do RQG Dzone https://dzone.com/articles/testing-n1ql-sql-for-json
Compartilhe este artigo
Receba atualizações do blog do Couchbase em sua caixa de entrada
Esse campo é obrigatório.

Autor

Postado por Ajay Bhullar

Ajay Bhullar é engenheiro de software testador no Couchbase há 2 anos. Ajay está trabalhando em como os ANSI JOINs do Couchbase são testados e, na versão 5.5 do Couchbase, como você pode executar junções usando a sintaxe padrão ANSI.

Deixe um comentário

Pronto para começar a usar o Couchbase Capella?

Iniciar a construção

Confira nosso portal do desenvolvedor para explorar o NoSQL, procurar recursos e começar a usar os tutoriais.

Use o Capella gratuitamente

Comece a trabalhar com o Couchbase em apenas alguns cliques. O Capella DBaaS é a maneira mais fácil e rápida de começar.

Entre em contato

Deseja saber mais sobre as ofertas do Couchbase? Deixe-nos ajudar.