Consulta SQL++ / N1QL

Abordagens para otimização de consultas em NoSQL

Um homem voltou para casa depois de dar a volta ao mundo por onze anos. No dia seguinte, quando ele disse à esposa que estava indo para a loja da esquina, ela lhe perguntou: "Você está fazendo o caminho mais curto ou o mais longo?".

As consultas podem ser executadas de várias maneiras diferentes. Todos os caminhos levam ao mesmo resultado de consulta. A ferramenta NoSQL e de otimização de consultas avalia as possibilidades e seleciona o plano eficiente. A eficiência é medida em latência e taxa de transferência, dependendo da carga de trabalho. O custo da memória, da CPU e do uso do disco é adicionado ao custo de um plano em um otimizador baseado em custos.

Agora, na maioria dos casos, um Banco de dados NoSQL terá Consulta do tipo SQL suporte a idiomas. Portanto, um bom otimizador é obrigatório. Quando não se tem um bom otimizador, os desenvolvedores têm de conviver com restrições de recursos e os DBAs têm de conviver com problemas de desempenho de consultas NoSQL.

Otimizador de banco de dados para melhorar as pesquisas de desempenho de NoSQL

A otimização de consultas NosSQL permite que você escolha um índice ideal e caminhos de acesso para executar a pesquisa. Em um nível muito alto, os otimizadores de SQL decidem o seguinte antes de criar a árvore de execução:

  1. Reescrita de consultas com base em heurística, custo ou ambos.
    • Assim como um editor remove palavras desnecessárias de um texto, o trabalho de reescrita de consultas pode variar desde a eliminação de predicados desnecessários até o achatamento de subconsultas, conversão de LEFT OUTER JOINS apropriados em INNER JOINS, dobra de tabelas derivadas etc.
  2. Seleção de índice.
    • Selecionar o(s) índice(s) ideal(is) para cada tabela (espaços-chave no Couchbase N1QL, coleção no caso das práticas recomendadas de desempenho do MongoDB)
    • Dependendo do índice selecionado, escolha os predicados a serem enviados para baixo, veja se a consulta está coberta ou não, decida sobre a estratégia de classificação e paginação.
  3. Reordenação de junções
    • (A INNER JOIN B INNER JOIN C) é equivalente a (B INNER JOIN C INNER JOIN A). O otimizador terá de determinar a melhor maneira de sequenciar essas uniões.
  4. Tipo de união
    • Os bancos de dados podem implementar vários tipos de algoritmos de união: loop aninhado, hash, mesclagem de classificação, ziguezague, estrela (floco de neve) etc. Dependendo da estrutura e do custo, o otimizador terá de decidir o tipo de algoritmo de união para cada operação de união.

Considere o caso da restrição do MongoDB. "Uma coleção pode ter no máximo um texto índice".  https://docs.mongodb.com/manual/core/index-text/#restrictions Além disso, ele documenta algumas outras restrições. Para este artigo, será suficiente explicar essa única restrição.

 

Por que você deve se preocupar com essa restrição?

  1. O MongoDB e outros bancos de dados NoSQL incentivam você a desnormalizar (agregar) seu esquema para criar um único documento grande que represente um objeto: um cliente, um parceiro etc., de modo que a maioria das suas operações ocorra em um único documento (JSON). Assim, um único documento de cliente pode conter informações do cliente, pedidos do cliente, informações de remessa do cliente, informações de faturamento do cliente. Ter um único índice de pesquisa significa que você precisa criar um único índice MUITO GRANDE que combine todos os campos que você deseja pesquisar. O problema é o seguinte: quando você pesquisa o endereço do cliente, não quer ver o endereço de entrega. Quando você pesquisa o orderid de remessa, não quer ver o orderid retornado.
  2. Você pode criar vários índices em escalares no MongoDB. Por que a restrição no índice de texto?

Por que o índice de texto do MongoDB é restrito a um índice por coleção?  

    • É o número de índices de texto? Os índices de pesquisa geralmente são criados com um estrutura de dados de árvore invertida. Mas, O MongoDB optou por criar com o índice B-Tree. É improvável que esse seja o problema.
    • É o tamanho dos índices de texto? Os índices de texto geram uma matriz de tokens no texto e os indexam. Portanto, é um índice de matriz. Seu tamanho pode crescer exponencialmente quando você usa um índice de matriz. O tamanho do índice aumenta linearmente com o número de palavras indexadas e não com o número de documentos. Isso pode causar problemas.
    • É um problema com o otimizador? Quando você tem vários índices, o otimizador terá que escolher o índice correto para a consulta. Se você restringir a um índice de texto, a escolha será fácil. Esse é um sintoma de um problema maior nas técnicas de otimização do MongoDB - ele toma decisões adhoc que resultam em restrições como essa.

A linguagem de plano de consulta do MongoDB é simplista, mesmo que esteja tentando imitam as operações do SQL.. Vamos ver como a ferramenta de otimização de consultas do MongoDB lida com isso.

  1. Reescrita de consulta:  Sem suporte. As consultas do MongoDB são simplistas nos métodos find(), save(), remove(), update(). O pipeline de agregação é processual e detalhado. Embora seja teoricamente possível reescrever, não há nada na documentação ou no plano que indique qualquer reescrita de consulta.
  2. Seleção de índice: Com suporte. O otimizador do MongoDB tenta escolher um índice adequado para cada parte da consulta e o índice pode/deve ser usado. Mais sobre isso abaixo.
  3. Reordenação de junções: Sem suporte. O $lookup do MongoDB faz parte da estrutura de agregação complicada em que a consulta é escrita como um pipeline Unix, uma abordagem processual.  
  4. Seleção do tipo de união: Sem suporte já que há apenas um tipo de junção no MongoDB. O MongoDB tem um suporte de junção externa esquerda restrita por meio do operador $lookup - não há suporte para arrays na condição de junção. Se você usar o $lookup, o otimizador usará automaticamente o algoritmo de junção padrão. Não há menção do tipo de união feita.  

Essencialmente, a otimização de consultas do MongoDB só faz a seleção de índices antes de criar o plano de execução. No entanto, a otimização de consultas no MongoDB parece selecionar os índices de forma estranha - nem por regra nem por estatística.  

  1. Escolha um índice aleatório em um ou mais índices qualificados.
  2. Use esse plano se uma consulta subsequente corresponder aos predicados da consulta, mesmo que as constantes, seletividades e cardinalidades sejam diferentes.
  3. Em seguida, em tempo de execução, se a varredura de índice retornar mais de 100 chaves (!), executa cada um dos planos alternativos para ver qual deles retorna as chaves primeiro. Em algum momento, ele aborta a execução paralela e escolhe um deles. Ele também substitui o plano em seu cache de planos.

Essa é uma única coleção com 4 índices em (x), (y), (x, y) e (y, x). Agora, veja isso:

Mesmo nessa estrutura simples de documento, o MongoDB seleciona o índice em (y), embora a consulta tenha filtros em x e y: ({x:{$gt:0}, y:99}).

Para gerenciar todas essas incertezas e os problemas de desempenho que elas acarretarão, o MongoDB fornece um número de APIs para gerenciar o cache do plano de consultaSe o usuário não tiver uma entrada de cache específica, ele poderá liberar todo o cache do plano. Em vez de desenvolver aplicativos, os desenvolvedores e DBAs do MongoDB precisam gerenciar o cache de planos. Os desenvolvedores e DBAs não precisam gerenciar o cache de planos em outros bancos de dados corporativos.

Voltemos à pergunta original: Por que não é possível criar vários índices de texto no MongoDB?

A criação de vários índices não deveria ser um problema se eles simplesmente o permitissem. A problema real é que, quando você fornece um predicado de texto em sua consulta, o otimizador do MongoDB não consegue escolher o índice correto. Ele não pode validar esses índices de texto em relação ao predicado de texto. O otimizador do MongoDB não segue uma lógica natural ou uma estrutura lógica. Daí a restrição.

E isso pode até machucá-lo!

O Couchbase N1QL adicionou o índice de texto ao N1QL para a próxima versão. Veja os detalhes em https://www.couchbase.com/blog/n1ql-and-search-how-to-leverage-fts-index-in-n1ql-query/. Os usuários podem criar qualquer número de índices de texto, e o otimizador escolherá um índice qualificado (classificável) e o utilizará. Ele também é compatível com a pesquisa durante uniões, varreduras pós-índice, etc., porque o otimizador entende o predicado de pesquisa e as camadas em sua lógica de decisão. Não há nenhuma nova API ou novo plano para gerenciar. Esse é o poder do Couchbase!

Recursos:
  1. Uma visão geral da otimização de consultas em sistemas relacionais: https://web.stanford.edu/class/cs345d-01/rl/chaudhuri98.pdf
  2. Um mergulho profundo na otimização de consultas N1QL do Couchbase: https://dzone.com/articles/a-deep-dive-into-couchbase-n1ql-query-optimization
  3. https://docs.mongodb.com/manual/reference/method/js-plan-cache/
  4. https://docs.mongodb.com/manual/core/query-plans/
  5. https://docs.mongodb.com/manual/reference/method/js-plan-cache/

 

Compartilhe este artigo
Receba atualizações do blog do Couchbase em sua caixa de entrada
Esse campo é obrigatório.

Autor

Postado por Keshav Murthy

Keshav Murthy é vice-presidente de P&D da Couchbase. Anteriormente, ele trabalhou na MapR, IBM, Informix e Sybase, com mais de 20 anos de experiência em design e desenvolvimento de bancos de dados. Ele liderou a equipe de P&D de SQL e NoSQL na IBM Informix. Recebeu dois prêmios President's Club na Couchbase e dois Outstanding Technical Achievement Awards na IBM. Keshav é bacharel em Ciência da Computação e Engenharia pela Universidade de Mysore, Índia, detém dez patentes nos EUA e tem três patentes pendentes nos EUA.

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.