O SQL existe há muuuuito tempo. É uma maneira muito intuitiva e eficiente de processar dados estruturados e tem sido a escolha para bancos de dados há muitos anos. No entanto, com o mundo dos BIG DATA, os dados velocidade, variedade e volume. O SQL pode enfrentar os 2 "v" está bem com as otimizações: "velocidade" e "volume". Na verdade, muitos dos novos dialetos do SQL (N1QL, Spark, U-SQL, Impala, Drill e outros) estão fazendo exatamente isso. No entanto, "variedade" é um jogo diferente! O Big Data é complexo no novo mundo; ele tem um esquema imprevisível, em constante evolução e irregular, valores esparsos e estruturas profundamente aninhadas. Para isso, o SQL precisa ser ampliado!
Bem, estou muito animado em informar que criamos o N1QL no Couchbase Server 4 para resolver exatamente esses problemas! O N1QL pode percorrer facilmente as estruturas complexas do JSON (o padrão de serialização de fato para dados complexos). Usando o N1QL, você pode trabalhar não apenas com NULLs, mas também com atributos que são FALTANDO em vários formatos de JSON que você processa. OU você pode usar operadores como QUALQUER/TODO para consultar matrizes incorporadas no documento JSON. OU você pode usar comandos como UNNEST E NEST que pode achatar ou desaninhar matrizes aninhadas. Há muitas dessas extensões poderosas para serem contadas aqui, portanto, não farei isso. Em vez disso, vou mostrar uma joia oculta que foi publicada originalmente aqui por Gerald. Essa gema é muito útil com agregados se você estiver usando o N1QL em comparação com um banco de dados relacional como o SQL Server.
Uma das grandes vantagens do N1QL é sua capacidade de entender os tipos de matriz. Funções de agregação como MAX() não são revolucionárias, mas com as adições de aninhamento e matrizes, algo tão simples como MAX() pode ser superpoderoso. Uma observação antes de me aprofundar: vou escolher o TSQL e o SQL Server porque contribuí para o TSQL em minha vida anterior na Microsoft. No entanto, isso também se aplica ao Oracle, Postgres, Mysql, Informix ou DB2 e muito mais... Ok, então: Imagine tentar encontrar os atributos do produto que tem o preço MÁXIMO. No SQL Server, essa é uma consulta bastante simples de escrever usando TSQL;
|
1 2 3 |
SELECT productID, name FROM t1 WHERE price = (SELECT MAX(price) FROM t1) GO |
Isso é bom. Aqui está o resultado - o produto com o preço mais alto é o produto chamado "c" com ID 3.
|
1 2 3 4 |
productID name ----------- ----------------------------------------------------------------- 3 c |
Esta é a aparência do plano de execução. Basicamente, o plano de execução procura o valor do preço MAX. Uma vez que você tenha o valor, é uma junção de loop aninhado para pesquisar os outros atributos do produto na tabela, como productID e name.
|
1 2 3 4 5 6 7 8 |
Stmt Text --------------------------------------------------------------------------------------------- select productID, name from t1 where price = (select max(price) from t1) |--Nested Loops(Inner Join, WHERE:([Expr1004]=[test].[dbo].[t1].[price])) |--Stream Aggregate(DEFINE:([Expr1004]=MAX([test].[dbo].[t1].[price]))) | |--Clustered Index Scan(OBJECT:([test].[dbo].[t1].[PK__t1__2D10D14A7FD17868])) |--Clustered Index Scan(OBJECT:([test].[dbo].[t1].[PK__t1__2D10D14A7FD17868])) |
No entanto, o N1QL tem uma grande vantagem aqui. Como ele pode processar MAX() com matrizes, você pode retornar todos os atributos do documento sem uma verificação adicional.
|
1 |
SELECT MAX([price, {productID, name]) FROM test; |
OU você pode simplesmente retornar o documento completo usando a seguinte consulta;
|
1 |
SELECT MAX([price, test]) FROM test; |
Vamos dar uma olhada no plano de execução da consulta N1QL. Aqui vem o spoiler: você vê uma única operação FETCH que pode executar o MAX e a projeção é feita sem um segundo FETCH.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
cbq>explain select MAX([price,test])from test; { "requestID":"b735ce5f-700c-4740-a065-6d4ba681129f", "signature":"json", "results":[ { "#operator":"Sequence", "~children":[ { "#operator":"PrimaryScan", "index":"#primary", "keyspace":"test", "namespace":"default", "using":"gsi" }, { "#operator":"Parallel", "~child":{ "#operator":"Sequence", "~children":[ { "#operator":"Fetch", "keyspace":"test", "namespace":"default" }, { "#operator":"InitialGroup", "aggregates":[ "max([(`test`.`price`), `test`])" ], "group_keys":[] } ] } }, { "#operator":"IntermediateGroup", "aggregates":[ "max([(`test`.`price`), `test`])" ], "group_keys":[] }, { "#operator":"FinalGroup", "aggregates":[ "max([(`test`.`price`), `test`])" ], "group_keys":[] }, { "#operator":"Parallel", "~child":{ "#operator":"Sequence", "~children":[ { "#operator":"InitialProject", "result_terms":[ { "expr":"max([(`test`.`price`), `test`])" } ] }, { "#operator":"FinalProject" } ] } } ] } ], "status":"success", "metrics":{ "elapsedTime":"1.8224ms", "executionTime":"1.7614ms", "resultCount":1, "resultSize":2347 } } |
Embora esse seja um truque muito legal e um grande ganho de desempenho, apenas arranhamos a superfície do que o N1QL é capaz de fazer. Há muito mais a ser descoberto com o N1QL. Você pode começar a usar o Couchbase Server e o N1QL aqui com o Guia de introdução.
-------------------
A propósito, se você quiser experimentar isso com o SQL Server 2016 e o Couchbase 4, aqui estão os scripts para ver isso em ação;
Script do servidor SQL
Observação: execute isso em um banco de dados chamado "teste"
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
create table t1(productID int primary key, price int, name varchar(128)); go insert into t1(productID,price,name) values(1,10,'a'); insert into t1(productID,price,name) values(2,9,'b'); insert into t1(productID,price,name) values(3,12,'c'); insert into t1(productID,price,name) values(4,11,'d'); insert into t1(productID,price,name) values(5,1,'e'); go set statistics profile on go select max(price),productID,name from t1 go --Msg 8120, Level 16, State 1, Line 10 --Column 't1.productID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. select productID, name from t1 where price = (select max(price) from t1) go |
Aqui está o script do servidor Couchbase
Observação: crie um bucket chamado "teste"
insert into test(key,value) values("1",{productID:1, price:10, name:'a'});
|
1 2 3 4 5 6 7 8 9 |
insert into test(key,value) values("1",{productID:1, price:10, name:'a'}); insert into test(key,value) values("2",{"productID":2, "price":9, "name":"b"}); insert into test(key,value) values("3",{"productID":3, "price":12, "name":"c"}); insert into test(key,value) values("4",{"productID":4, "price":11, "name":"d"}); insert into test(key,value) values("5",{"productID":5, "price":1, "name":"e"}); create primary index on test; select max(price, productID, name) from t1; select max([price, test]) from test; explain select max([price, test]) from test; |