A Structured Query Language (SQL) foi originalmente projetada como uma linguagem de consulta intuitiva para armazenamentos de dados relacionais. O NoSQL, relativamente recente em comparação, ainda exige compatibilidade com o SQL, pois muitas ferramentas e aplicativos de BI o entendem. O Couchbase oferece suporte à sua própria linguagem de consulta, N1QLque estende o SQL para consultar documentos JSON armazenados em Servidor Couchbase. Os drivers Simba Couchbase ODBC e JDBC permitem que os usuários "tenham o bolo e o comam também", possibilitando que os usuários aproveitem tanto o SQL quanto o N1QL. Uma das maneiras de conseguir isso é com o Execução de consulta colaborativa (CQE) oferecido pelo SimbaEngine X. Este artigo explica como os drivers do Simba Couchbase usam o CQE, aproveitando as semelhanças entre o SQL e o N1QL, para garantir o desempenho ideal.
Operação JOIN
N1QL suporta Junções de pesquisaque podem ser traduzidos de forma aproximada em JOINs análogos no SQL. Aqui, explicaremos como os drivers do Simba Couchbase aproveitam o recurso CQE para transmitir as operações JOIN para o Couchbase Server.
Considere o conjunto de dados de amostra de cerveja com documentos de cerveja e cervejaria. Usando os drivers do Simba Couchbase, esses documentos podem ser mapeados para duas tabelas diferentes - cerveja e cervejaria - e os usuários podem executar consultas JOIN nessas duas tabelas.
Digamos que um usuário queira descobrir todas as cervejas fabricadas no estado da Califórnia, ele emitiria uma instrução SQL da seguinte forma:
|
1 |
SELECT beer.name, brewery.name FROM beer JOIN brewery ON beer.brewery_id=brewery.PK WHERE brewery.state='California' |
Para gerar o resultado dessa consulta SQL, você teria que fazer o seguinte:
- Recuperar todos os documentos de cerveja do Couchbase Server para o cliente
- Recuperar todos os documentos de fermentação do Couchbase Server para o cliente
- Executar a união
- Filtre os resultados em que o estado é Califórnia.
Isso não é muito eficiente, pois pode sobrecarregar o lado do cliente se as tabelas de união forem muito grandes. Além disso, as operações JOIN e WHERE são compatíveis com o N1QL. A transferência da carga para o lado do servidor resultaria em melhor desempenho.
Os drivers do Simba Couchbase fazem exatamente isso. Com o CQE, os drivers do Simba Couchbase traduzem o SQL fornecido em N1QL análogo, que pode ser passado para o Couchbase Server para execução. A instrução SQL acima pode ser traduzida para N1QL da seguinte forma:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
SELECT `$sb_c5_name`,`$sb_c6_name` FROM `beer-sample` `$sb_t0_beer` JOIN `beer-sample` `$sb_t1_brewery` ON KEYS TOSTRING(IFMISSING(`$sb_t0_beer`.`brewery_id`,NULL)) LET `$sb_c0_PK` = META(`$sb_t0_beer`).id, `$sb_c1_TableType` = TOSTRING(IFMISSING(`$sb_t0_beer`.`type`,NULL)), `$sb_c2_PK` = META(`$sb_t1_brewery`).id, `$sb_c3_TableType` = TOSTRING(IFMISSING(`$sb_t1_brewery`.`type`,NULL)), `$sb_c4_state` = TOSTRING(IFMISSING(`$sb_t1_brewery`.`state`,NULL)), `$sb_c5_name` = TOSTRING(IFMISSING(`$sb_t0_beer`.`name`,NULL)), `$sb_c6_name` = TOSTRING(IFMISSING(`$sb_t1_brewery`.`name`,NULL)) WHERE (`$sb_c0_PK`!='~~~SchemaMap') AND(`$sb_c1_TableType` = 'beer') AND(`$sb_c2_PK`!='~~~SchemaMap') AND(`$sb_c3_TableType` = 'brewery') AND(`$sb_c4_state` = "California"); |
Por baixo do capô, os drivers do Simba Couchbase usam o Simba SQL Engine para análise, preparação e execução de consultas. Antes da execução da consulta, os drivers criam uma representação de Árvore de Expressão Algébrica (AE-Tree). A instrução SQL assume essa forma pouco antes de o Simba SQL Engine transformá-la em um plano de execução e executá-la. Antes da execução, o driver pode revisar o plano e verificar se pode executar alguma parte dele. Isso é chamado de etapa de passagem para baixo.
Pouco antes da etapa de passagem para baixo (conforme descrito na seção Otimização do AETree artigo), a árvore AE tem a seguinte aparência:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
AEQuery AEProject AEJoin: AE_INNER_JOIN AETable: cbdefault.beer-sample.beer AESelect AETable: cbdefault.beer-sample.brewery AEComparison: EQ AEValueList AEColumn: "cbdefault"."beer-sample"."brewery"."state" AEValueList AELiteral: California; Character String Literal AEComparison: EQ AEValueList AEColumn: "cbdefault"."beer-sample"."beer"."brewery_id" AEValueList AEColumn: "cbdefault"."beer-sample"."brewery"."PK" AEValueList AEColumn: "cbdefault"."beer-sample"."beer"."name" AEColumn: "cbdefault"."beer-sample"."brewery"."name" |
E, após a transferência, o AETree tem a seguinte aparência:
|
1 2 |
AEQuery AETable: beer_JOIN_brewery |
Como você pode ver, a AE-Tree contém apenas um nó que representa a tabela unida, o que significa que todo o resto, inclusive a união e a filtragem, é passado para o Couchbase Server. Menos dados enviados através do fio do Couchbase Server para o driver e menos operações feitas no lado do cliente = melhor desempenho!
Operação UNNEST
O N1QL suporta a cláusula UNNEST, que conceitualmente executa uma junção de uma matriz aninhada com seu objeto pai.
Nos drivers do Simba Couchbase, qualquer matriz aninhada é mapeada para uma tabela virtual e os usuários podem se unir à tabela principal com a tabela virtual. Isso usa novamente o recurso CQE do SimbaEngine X e aproveita a cláusula N1QL UNNEST.
Por exemplo, todos os documentos de cervejarias no conjunto de dados de amostras de cerveja contêm matrizes aninhadas chamadas brewery_address. Nos drivers do Simba Couchbase, esses documentos são mapeados para uma tabela brewery e uma tabela virtual brewery_address. Digamos que um usuário queira obter todos os nomes de cervejarias depois de unir brewery e brewery_address, ele emitiria uma instrução SQL da seguinte forma:
|
1 |
SELECT brewery.name FROM brewery JOIN brewery_address ON brewery.PK=brewery_address.PK; |
Os drivers do Simba Couchbase traduzem a instrução SQL acima para N1QL da seguinte forma:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
SELECT `$sb_c4_name` FROM `beer-sample` `$sb_t0_brewery` UNNEST `$sb_t0_brewery`.`address` `$sb_t1_brewery_address` LET `$sb_c0_PK` = META(`$sb_t0_brewery`).id, `$sb_c1_TableType` = TOSTRING(IFMISSING(`$sb_t0_brewery`.`type`,NULL)), `$sb_c2_PK` = META(`$sb_t0_brewery`).id, `$sb_c3_TableType` = TOSTRING(IFMISSING(`$sb_t0_brewery`.`type`,NULL)), `$sb_c4_name` = TOSTRING(IFMISSING(`$sb_t0_brewery`.`name`,NULL)) WHERE (`$sb_c0_PK`!='~~~SchemaMap') AND(`$sb_c1_TableType` = 'brewery') AND(`$sb_c2_PK`!='~~~SchemaMap') AND(`$sb_c3_TableType` = 'brewery'); |
Antes da transferência, a árvore AE tem a seguinte aparência:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
AEQuery AEProject AEJoin: AE_INNER_JOIN AETable: cbdefault.beer-sample.brewery AETable: cbdefault.beer-sample.brewery_address AEComparison: EQ AEValueList AEColumn: "cbdefault"."beer-sample"."brewery"."PK" AEValueList AEColumn: "cbdefault"."beer-sample"."brewery_address"."PK" AEValueList AEColumn: "cbdefault"."beer-sample"."brewery"."name" |
Após a transferência, a árvore AE tem a seguinte aparência:
|
1 2 |
AEQuery AETable: brewery_JOIN_brewery_address |
Como você pode ver, a AE-Tree novamente contém apenas um nó que representa a tabela unida, o que significa que todo o resto é passado para o Couchbase Server para execução. Novamente, quanto mais operações ocorrerem no lado do servidor e quanto menos dados retornarem pelo fio para o driver, mais eficiente será a consulta.
Esses dois exemplos destacam como os drivers do Simba Couchbase utilizam todo o potencial do Couchbase Server, passando as operações N1QL compatíveis para o servidor executar. Para quaisquer recursos SQL que não sejam compatíveis com o N1QL, os drivers executam as operações (no lado do cliente). Dessa forma, os drivers garantem a amplitude do suporte para SQL e N1QL, bem como o alto desempenho.
Agora é sua vez
Faça o download de uma avaliação gratuita de Drivers ODBC/JDBC do Couchbase e experimente-os com o novo Couchbase Server 4.5!