Solução de problemas de consultas lentas

ATENÇÃO

AEM 6.4 chegou ao fim do suporte estendido e esta documentação não é mais atualizada. Para obter mais detalhes, consulte nossa períodos de assistência técnica. Encontre as versões compatíveis here.

Classificações de consulta lentas

Há 3 classificações principais de consultas lentas no AEM, listadas por gravidade:

  1. Consultas sem índice

    • Queries que fazem not resolver para um índice e percorrer o conteúdo do JCR para coletar resultados
  2. Consultas restritas incorretamente (ou com escopo)

    • Consultas que são resolvidas em um índice, mas devem atravessar todas as entradas de índice para coletar resultados
  3. Grandes consultas de conjunto de resultados

    • Consultas que retornam números muito grandes de resultados

As primeiras 2 classificações de consultas (sem índice e pouco restritas) são lentas, pois forçam o mecanismo de consulta Oak a inspecionar cada potencial resultado (nó de conteúdo ou entrada de índice) para identificar qual pertence ao real conjunto de resultados.

O ato de inspecionar cada resultado potencial é o chamado Traversing.

Uma vez que cada resultado potencial deve ser inspecionado, o custo para determinar o conjunto de resultados real cresce linearmente com o número de resultados potenciais.

A adição de restrições de consulta e índices de ajuste permite que os dados do índice sejam armazenados em um formato otimizado, permitindo uma recuperação rápida do resultado e reduz ou elimina a necessidade da inspeção linear de conjuntos de resultados potenciais.

No AEM 6.3, por padrão, quando uma travessia de 100.000 é atingida, o query falha e gera uma exceção. Esse limite não existe por padrão nas versões AEM anteriores ao AEM 6.3, mas pode ser definido por meio das Configurações do mecanismo de consulta Apache Jackrabbit Configuração OSGi e QueryEngineSettings JMX bean (propriedade LimitReads).

Detectando Consultas Sem Índice

Durante o desenvolvimento

Explicar all consultas e garantir que seus planos de query não contenham a variável /* traverse explicação. Exemplo de plano de consulta de percurso:

  • PLANO: [nt:unstructured] as [a] /* traverse "/content//*" where ([a].[unindexedProperty] = 'some value') and (isdescendantnode([a], [/content])) */

Pós-implantação

  • Monitore o error.log para consultas transversais sem índice:

    • *INFO* org.apache.jackrabbit.oak.query.QueryImpl Traversal query (query without index) ... ; consider creating and index
    • Essa mensagem só será registrada se nenhum índice estiver disponível e se a consulta potencialmente atravessar muitos nós. As mensagens não são registradas se um índice estiver disponível, mas a quantidade de travamento é pequena e, portanto, rápida.
  • Visite o AEM Desempenho da consulta console de operações e Explicar consultas lentas que procuram traversal ou nenhuma explicação de consulta de índice.

Detecção de Consultas Mal Restritas

Durante o desenvolvimento

Explicar todas as consultas e garantir que elas sejam resolvidas em um índice ajustado para corresponder às restrições de propriedade da consulta.

  • A cobertura do plano de consulta ideal tem indexRules para todas as restrições de propriedade e, no mínimo, para as restrições de propriedade mais restritas no query.
  • Consultas que classificam resultados devem ser resolvidas para um Índice de propriedades do Lucene com regras de índice para as propriedades classificadas por orderable=true.

Por exemplo, o padrão cqPageLucene não tem uma regra de índice para jcr:content/cq:tags

Antes de adicionar a regra de índice cq:tags

  • cq:tags Regra de índice

    • Não existe imediatamente
  • Query Builder

    type=cq:Page
     property=jcr:content/cq:tags
     property.value=my:tag
    
  • Plano de consulta

    • [cq:Page] as [a] /* lucene:cqPageLucene(/oak:index/cqPageLucene?lang=pt-BR) *:* where [a].[jcr:content/cq:tags] = 'my:tag' */

Esse query resolve o cqPageLucene índice, mas porque não existe nenhuma regra de índice de propriedade para jcr:content ou cq:tags, quando essa restrição é avaliada, cada registro no cqPageLucene índice é verificado para determinar uma correspondência. Isso significa que se o índice contiver 1 milhão cq:Page nós, então 1 milhão de registros são verificados para determinar o conjunto de resultados.

Após adicionar a regra de índice cq:tags

  • cq:tags Regra de índice

    /oak:index/cqPageLucene/indexRules/cq:Page/properties/cqTags
     @name=jcr:content/cq:tags
     @propertyIndex=true
    
  • Query Builder

    type=cq:Page
     property=jcr:content/cq:tags
     property.value=myTagNamespace:myTag
    
  • Plano de consulta

    • [cq:Page] as [a] /* lucene:cqPageLucene(/oak:index/cqPageLucene?lang=pt-BR) jcr:content/cq:tags:my:tag where [a].[jcr:content/cq:tags] = 'my:tag' */

A adição de indexRule para jcr:content/cq:tags no cqPageLucene o índice permite cq:tags dados a serem armazenados de forma otimizada.

Quando um query com a variável jcr:content/cq:tags for executada, o índice poderá procurar resultados por valor. Isso significa que se 100 cq:Page nós myTagNamespace:myTag como valor, apenas esses 100 resultados são retornados e os outros 999.000 são excluídos das verificações de restrição, melhorando o desempenho em um fator de 10.000.

É claro que outras restrições de query reduzem os conjuntos de resultados qualificados e otimizam ainda mais a otimização de query.

Da mesma forma, sem uma regra de índice adicional para a variável cq:tags propriedade, até mesmo uma consulta de texto completo com uma restrição em cq:tags teria um desempenho ruim, pois os resultados do índice retornariam todas as correspondências de texto completo. A restrição em cq:tags seria filtrada depois.

Outra causa da filtragem pós-índice são as Listas de Controle de Acesso que geralmente são perdidas durante o desenvolvimento. Tente garantir que a consulta não retorne caminhos que possam estar inacessíveis ao usuário. Isso geralmente pode ser feito por uma melhor estrutura de conteúdo, juntamente com a disponibilização de uma restrição de caminho relevante na query.

Uma maneira útil de identificar se o índice Lucene está retornando muitos resultados para retornar um subconjunto muito pequeno como resultado de query é ativar logs DEBUG para org.apache.jackrabbit.oak.plugins.index.lucene.LucenePropertyIndex e veja quantos documentos estão sendo carregados do índice. O número de eventuais resultados versus o número de documentos carregados não deve ser desproporcionado. Para obter mais informações, consulte Registro.

Pós-implantação

  • Monitore o error.log para consultas transversais:

    • *WARN* org.apache.jackrabbit.oak.spi.query.Cursors$TraversingCursor Traversed ### nodes ... consider creating an index or changing the query
  • Visite o AEM Desempenho da consulta console de operações e Explicar consultas lentas que procuram planos de consulta que não resolvem restrições de propriedade de consulta para regras de propriedade de índice.

Detectando Consultas de Conjunto de Resultados Grandes

Durante o desenvolvimento

Defina limites baixos para oak.queryLimitInMemory (por exemplo, 10000) e oak.queryLimitReads (por exemplo, 5000) e otimizar a consulta cara ao hit de um UnsupportedOperationException dizendo "A consulta leu mais de x nós…"

Isso ajuda a evitar consultas que consomem muitos recursos (ou seja, não é suportada por qualquer índice ou pelo índice de cobertura inferior). Por exemplo, uma consulta que lê nós 1M levaria a muitas E/S e afetaria negativamente o desempenho geral do aplicativo. Portanto, qualquer query que falhe devido a limites acima deve ser analisada e otimizada.

Pós-implantação

  • Monitore os logs para consultas que acionam grande passagem de nó ou grande consumo de memória heap :

    • *WARN* ... java.lang.UnsupportedOperationException: The query read or traversed more than 100000 nodes. To avoid affecting other tasks, processing was stopped.
    • Otimizar a consulta para reduzir o número de nós atravessados
  • Monitore os logs para consultas que acionam grande consumo de memória heap :

    • *WARN* ... java.lang.UnsupportedOperationException: The query read more than 500000 nodes in memory. To avoid running out of memory, processing was stopped
    • Otimizar a consulta para reduzir o consumo de memória heap

Para AEM versões 6.0 - 6.2, você pode ajustar o limite para a travessia do nó por meio de parâmetros da JVM no script de início de AEM para impedir que consultas grandes sobrecarreguem o ambiente. Os valores recomendados são :

  • -Doak.queryLimitInMemory=500000
  • -Doak.queryLimitReads=100000

No AEM 6.3, os 2 parâmetros acima são pré-configurados por padrão e podem ser modificados por meio do QueryEngineSettings do OSGi.

Mais informações disponíveis em : https://jackrabbit.apache.org/oak/docs/query/query-engine.html#Slow_Queries_and_Read_Limits

Ajuste do desempenho da consulta

O lema da otimização de desempenho de consulta no AEM é:

"Quanto mais restrições, melhor."

A seguir, são apresentados os ajustes recomendados para garantir o desempenho da consulta. Primeiro ajuste a consulta, uma atividade menos intrusiva e, em seguida, se necessário, ajuste as definições de índice.

Ajustando a Instrução de Consulta

AEM suporta os seguintes idiomas de consulta:

  • Query Builder
  • JCR-SQL2
  • XPath

O exemplo a seguir usa o Query Builder como a linguagem de consulta mais comum usada por AEM desenvolvedores, no entanto, os mesmos princípios são aplicáveis a JCR-SQL2 e XPath.

  1. Adicione uma restrição do tipo de nó para que a consulta resolva para um Índice de propriedades do Lucene existente.

    • Consulta não otimizada

       property=jcr:content/contentType
       property.value=article-page
      
    • Consulta otimizada

       type=cq:Page
       property=jcr:content/contentType
       property.value=article-page
      

    Consultas sem uma força de restrição de tipo de nó AEM assumir a variável nt:base nodetype, que cada nó no AEM é um subtipo de, resultando efetivamente em nenhuma restrição de tipo de nó.

    Configuração type=cq:Page restringe esta consulta somente cq:Page e resolve a consulta para AEM cqPageLucene, limitando os resultados a um subconjunto de nós (somente cq:Page nós) em AEM.

  2. Ajuste a restrição do tipo de nó da consulta para que ela seja resolvida para um Índice de propriedades Lucene existente.

    • Consulta não otimizada

      type=nt:hierarchyNode
      property=jcr:content/contentType
      property.value=article-page
      
    • Consulta otimizada

      type=cq:Page
      property=jcr:content/contentType
      property.value=article-page
      

    nt:hierarchyNode é o tipo de nó principal de cq:Pagee assumindo jcr:content/contentType=article-page é aplicado somente a cq:Page nós via nosso aplicativo personalizado, esta consulta retornará somente cq:Page nós onde jcr:content/contentType=article-page. No entanto, essa é uma restrição subideal, pois:

    • Outro nó herda de nt:hierarchyNode (por exemplo, dam:Asset) adicionar desnecessariamente ao conjunto de resultados potenciais.
    • Não existe um índice fornecido AEM para nt:hierarchyNode, no entanto, como há um índice fornecido para cq:Page.

    Configuração type=cq:Page restringe esta consulta somente cq:Page e resolve a consulta para AEM cqPageLucene, limitando os resultados a um subconjunto de nós (somente nós cq:Page) em AEM.

  3. Ou ajuste as restrições de propriedade para que a consulta resolva para um Índice de propriedades existente.

    • Consulta não otimizada

        property=jcr:content/contentType
        property.value=article-page
      
    • Consulta otimizada

      property=jcr:content/sling:resourceType
      property.value=my-site/components/structure/article-page
      

    Alterar a restrição de propriedade de jcr:content/contentType (um valor personalizado) para a propriedade conhecida sling:resourceType permite que a query resolva para o índice de propriedade slingResourceType que indexa todo o conteúdo por sling:resourceType.

    Os índices de propriedade (em vez de Índices de propriedades do Lucene) são melhor usados quando a consulta não é discernível por tipo de nó e uma única restrição de propriedade domina o conjunto de resultados.

  4. Adicione a restrição de caminho mais estrita possível ao query. Por exemplo, preferir /content/my-site/us/en over /content/my-siteou /content/dam over /.

    • Consulta não otimizada

      type=cq:Page
      path=/content
      property=jcr:content/contentType
      property.value=article-page
      
    • Consulta otimizada

      type=cq:Page
      path=/content/my-site/us/en
      property=jcr:content/contentType
      property.value=article-page
      

    Escopo da restrição de caminho de path=/contentpara path=/content/my-site/us/en permite que os índices reduzam o número de entradas de índice que precisam ser inspecionadas. Quando a query puder restringir muito bem o caminho, além de apenas /content ou /content/dam, assegure-se de que o índice tenha evaluatePathRestrictions=true.

    Observe usando evaluatePathRestrictions aumenta o tamanho do índice.

  5. Sempre que possível, evite funções/operações de query como: LIKE e fn:XXXX dado que os seus custos são proporcionais ao número de resultados baseados em restrições.

    • Consulta não otimizada

      type=cq:Page
      property=jcr:content/contentType
      property.operation=like
      property.value=%article%
      
    • Consulta otimizada

      type=cq:Page
      fulltext=article
      fulltext.relPath=jcr:content/contentType
      

    A condição LIKE é lenta para avaliar, pois nenhum índice pode ser usado se o texto começar com um curinga ("%…'). A condição jcr:contains permite usar um índice de texto completo e, portanto, é preferível. Isso requer que o Índice de propriedades do Lucene resolvido tenha indexRule para jcr:content/contentType com analayzed=true.

    Uso de funções de consulta como fn:lowercase(..) pode ser mais difícil de otimizar, pois não há equivalentes mais rápidos (fora das configurações mais complexas e discretas do analisador de índice). É melhor identificar outras restrições de escopo para melhorar o desempenho geral da consulta, exigindo que as funções operem no menor conjunto possível de resultados potenciais.

  6. Esse ajuste é específico do Query Builder e não se aplica a JCR-SQL2 ou XPath.

    Use guessTotal do construtor de consultas quando o conjunto completo de resultados for não ​ imediatamente necessário.

    • Consulta não otimizada

      type=cq:Page
      path=/content
      
    • Consulta otimizada

      type=cq:Page
      path=/content
      p.guessTotal=100
      

    Para casos em que a execução da consulta é rápida, mas o número de resultados é grande, p guessTotal O é uma otimização crítica para consultas do Query Builder.

    p.guessTotal=100 instrui o Query Builder a coletar apenas os primeiros 100 resultados e definir um sinalizador booleano indicando se existem pelo menos mais um resultado (mas não quantos mais, já que a contagem desse número resultaria em lentidão). Essa otimização se sobressai para paginação ou casos de uso de carregamento infinito, onde apenas um subconjunto de resultados é exibido de forma incremental.

Ajuste de índice existente

  1. Se a consulta ideal for resolvida para um Índice de propriedades, não há mais nada para fazer, pois os Índices de propriedades são minimamente ajustáveis.

  2. Caso contrário, a consulta deve ser resolvida para um Índice de propriedades do Lucene. Se nenhum índice puder ser resolvido, vá para Criação de um novo Índice.

  3. Conforme necessário, converta a consulta para XPath ou JCR-SQL2.

    • Query Builder

      query type=cq:Page
      path=/content/my-site/us/en
      property=jcr:content/contentType
      property.value=article-page
      orderby=@jcr:content/publishDate
      orderby.sort=desc
      
    • XPath gerado da consulta do Query Builder

      /jcr:root/content/my-site/us/en//element(*, cq:Page)[jcr:content/@contentType = 'article-page'] order by jcr:content/@publishDate descending
      
  4. Forneça o XPath (ou JCR-SQL2) para Gerador de definição de índice Oak para gerar a definição otimizada do Índice de propriedades do Lucene.

    Definição de índice de propriedade do Lucene gerada

    - evaluatePathRestrictions = true
    - compatVersion = 2
    - type = "lucene"
    - async = "async"
    - jcr:primaryType = oak:QueryIndexDefinition
        + indexRules
        + cq:Page
            + properties
            + contentType
                - name = "jcr:content/contentType"
                - propertyIndex = true
            + publishDate
                - ordered = true
                - name = "jcr:content/publishDate"
    
  5. Mescle manualmente a definição gerada no Índice de propriedades do Lucene existente de forma aditiva. Tenha cuidado para não remover configurações existentes, pois elas podem ser usadas para atender a outros queries.

    1. Localize o Índice de propriedades do Lucene existente que abrange cq:Page (usando o Gerenciador de índices). Nesse caso, /oak:index/cqPageLucene.
    2. Identifique o delta de configuração entre a definição de índice otimizada (Etapa 4) e o índice existente (/oak:index/cqPageLucene?lang=pt-BR) e adicione as configurações ausentes do Índice otimizado à definição de índice existente.
    3. De acordo com AEM Práticas recomendadas de reindexação, uma atualização ou reindexação está em ordem, com base em se o conteúdo existente será afetado por essa alteração de configuração de índice.

Criar um novo índice

  1. Verifique se a consulta não resolve um Índice de propriedades do Lucene existente. Se isso acontecer, consulte a seção acima sobre ajuste e índice existente.

  2. Conforme necessário, converta a consulta para XPath ou JCR-SQL2.

    • Query Builder

      type=myApp:Author
      property=firstName
      property.value=ira
      
    • XPath gerado da consulta do Query Builder

      //element(*, myApp:Page)[@firstName = 'ira']
      
  3. Forneça o XPath (ou JCR-SQL2) para Gerador de definição de índice Oak para gerar a definição otimizada do Índice de propriedades do Lucene.

    Definição de índice de propriedade do Lucene gerada

    - compatVersion = 2
    - type = "lucene"
    - async = "async"
    - jcr:primaryType = oak:QueryIndexDefinition
        + indexRules
        + myApp:AuthorModel
            + properties
            + firstName
                - name = "firstName"
                - propertyIndex = true
    
  4. Implante a definição do Índice de propriedades do Lucene gerado.

    Adicione a definição XML fornecida pelo Gerador de Definição de Índice Oak para o novo índice ao projeto AEM que gerencia as definições de índice Oak (lembre-se de tratar as definições de índice Oak como código, já que o código depende delas).

    Implante e teste o novo índice seguindo o ciclo de vida normal de desenvolvimento de software AEM e verifique se a consulta resolve o índice e se a consulta é executada.

    Após a implantação inicial desse índice, o AEM preencherá o índice com os dados necessários.

Quando as consultas de índice e travessia estão corretas?

Devido a AEM arquitetura de conteúdo flexível, é difícil prever e garantir que as travessias das estruturas de conteúdo não evoluam ao longo do tempo para serem inaceitavelmente grandes.

Portanto, verifique se um índice atende a queries, exceto se a combinação de restrição de caminho e restrição de tipo de nó garantir que menos de 20 nós já foram atravessados.

Ferramentas de desenvolvimento de consultas

Adobe Suportado

  • Query Builder Debugger

    • Uma WebUI para executar consultas do Query Builder e gerar o XPath de suporte (para uso em Explain Query ou Oak Index Definition Generator).
    • Localizado em AEM em /libs/cq/search/content/querydebug.html
  • CRXDE Lite - Ferramenta de consulta

    • Uma WebUI para executar consultas XPath e JCR-SQL2.
    • Localizado em AEM em /crx/de/index.jsp > Ferramentas > Consulta…
  • Explicar consulta

    • Um painel de Operações de AEM que fornece uma explicação detalhada (Plano de consulta, tempo de consulta e número de resultados) para qualquer consulta XPATH ou JCR-SQL2 específica.
  • Consultas lentas/populares

    • Um painel AEM Operations listando as consultas lentas e populares recentes executadas em AEM.
  • Gerenciador de índice

    • Uma WebUI AEM Operations exibindo os índices na instância AEM; facilita a compreensão de quais índices já existem, podem ser direcionados ou aumentados.
  • Logs

    • Registro do construtor de consultas

      • DEBUG @ com.day.cq.search.impl.builder.QueryImpl
    • Log de execução da consulta Oak

      • DEBUG @ org.apache.jackrabbit.oak.query
  • Configuração OSGi das configurações do mecanismo de consulta Apache Jackrabbit

  • Mbean JMX NodeCounter

Comunidade suportada

  • Gerador de definição de índice Oak

    • Gere o índice ideal de propriedades do Lucence a partir das instruções de consulta XPath ou JCR-SQL2.
  • Plug-in do AEM Chrome

    • A extensão do navegador da Web Google Chrome que expõe os dados de log por solicitação, incluindo consultas executadas e seus planos de query, no console de ferramentas dev do navegador.
    • Exige Sling Log Tracer 1.0.2+ para ser instalado e ativado no AEM.

Nesta página