Há três classificações principais de consultas lentas no AEM, listadas por gravidade:
Consultas sem índice
Consultas pouco restritas (ou com escopo)
Consultas de conjunto de resultados grandes
As duas primeiras classificações de consultas (sem índice e pouco restritas) são lentas. Elas são lentas porque forçam o mecanismo de consulta do Oak a inspecionar cada potencial (nó de conteúdo ou entrada de índice) para identificar quais pertencem à real conjunto de resultados.
O ato de inspecionar cada resultado potencial é o que é chamado de Travessia.
Como 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 de índice sejam armazenados em um formato otimizado, permitindo uma recuperação rápida de resultados e reduz ou elimina a necessidade de inspeção linear de conjuntos de resultados em potencial.
No AEM 6.3, por padrão, quando um percurso de 100.000 é atingido, o query falha e lança 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 da configuração OSGi Apache Rabbit Query Engine Settings e do bean JMX QueryEngineSettings (propriedade LimitReads).
Explicar all consultas e garantir que seus planos de consulta não contenham a variável /* traverse explicações neles. Exemplo de plano de consulta de passagem:
[nt:unstructured] as [a] /* traverse "/content//*" where ([a].[unindexedProperty] = 'some value') and (isdescendantnode([a], [/content])) */
Monitore o error.log
para consultas de percurso sem índice:
*INFO* org.apache.jackrabbit.oak.query.QueryImpl Traversal query (query without index) ... ; consider creating and index
Visite o AEM Desempenho da consulta console de operações e Explicar consultas lentas que procuram explicação de percurso ou nenhuma consulta de índice.
Explique todas as consultas e verifique se elas são resolvidas em um índice ajustado para corresponder às restrições de propriedade da consulta.
indexRules
para todas as restrições de propriedade e, no mínimo, para as restrições de propriedade mais rigorosas na consulta.orderable=true.
cqPageLucene
não tem uma regra de índice para jcr:content/cq:tags
Antes de adicionar a regra de índice cq:tags
cq:regra de índice de tags
Consulta do Construtor de consultas
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' */
Essa consulta resolve para o cqPageLucene
índice, mas porque não existe nenhuma regra de índice de propriedade para jcr:content
ou cq:tags
, quando essa restrição for avaliada, cada registro no cqPageLucene
índice é verificado para determinar uma correspondência. Como tal, se o índice contiver 1 milhão de cq:Page
nós, então 1 milhão de registros são verificados para determinar o conjunto de resultados.
Depois de adicionar a regra de índice cq:tags
cq:regra de índice de tags
/oak:index/cqPageLucene/indexRules/cq:Page/properties/cqTags
@name=jcr:content/cq:tags
@propertyIndex=true
Consulta do Construtor de consultas
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 uma consulta com o jcr:content/cq:tags
for executada, o índice poderá pesquisar resultados por valor. Isso significa que se 100 cq:Page
os nós têm myTagNamespace:myTag
como valor, somente esses 100 resultados são retornados e os outros 999.000 são excluídos das verificações de restrição, melhorando o desempenho por um fator de 10.000.
Mais restrições de consulta reduzem os conjuntos de resultados qualificados e otimizam ainda mais a otimização da consulta.
Da mesma forma, sem uma regra de índice extra para o cq:tags
propriedade, até mesmo uma consulta de texto completo com uma restrição em cq:tags
teria um desempenho insatisfatório, pois os resultados do índice retornariam todas as correspondências de texto completo. A restrição em cq:tags seria filtrada após.
Outra causa da filtragem pós-índice são as Listas de controle de acesso, que muitas vezes são perdidas durante o desenvolvimento. Tente garantir que a consulta não retorne caminhos que podem ser inacessíveis para o usuário. Isso pode ser feito por uma estrutura de conteúdo melhor, juntamente com a restrição de caminho relevante na consulta.
Uma maneira útil de identificar se o índice Lucene está retornando muitos resultados para retornar um pequeno subconjunto como resultado de consulta é ativar os logs DEBUG para org.apache.jackrabbit.oak.plugins.index.lucene.LucenePropertyIndex
. Isso permite que você veja quantos documentos estão sendo carregados a partir do índice. O número de resultados eventuais versus o número de documentos carregados não deve ser desproporcional. Para obter mais informações, consulte Logs.
Monitore o error.log
para consultas de percurso:
*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.
Defina limites baixos para oak.queryLimitInMemory (por exemplo, 10000) e oak.queryLimitReads (por exemplo, 5000) e otimize a consulta cara ao acessar um UnsupportedOperationException dizendo "A consulta leu mais do que x nós…"
A definição de limites baixos ajuda a evitar consultas que consomem muitos recursos (ou seja, sem o suporte de qualquer índice ou com o suporte de um índice de cobertura menor). Por exemplo, uma consulta que lê um milhão de nós levaria a muita I/O e afetaria negativamente o desempenho geral do aplicativo. Portanto, qualquer query que falhar devido aos limites acima devem ser analisados e otimizados.
Monitore os logs de consultas que acionam travessia de nó grande ou consumo de memória de heap grande : "
*WARN* ... java.lang.UnsupportedOperationException: The query read or traversed more than 100000 nodes. To avoid affecting other tasks, processing was stopped.
Monitore os logs para consultas que acionam grande consumo de memória de heap:
*WARN* ... java.lang.UnsupportedOperationException: The query read more than 500000 nodes in memory. To avoid running out of memory, processing was stopped
Para versões do AEM 6.0 - 6.2, é possível ajustar o limite para passagem de nó por meio de parâmetros JVM no script de inicialização do AEM para evitar que grandes consultas sobrecarreguem o ambiente. Os valores recomendados são:
-Doak.queryLimitInMemory=500000
-Doak.queryLimitReads=100000
No AEM 6.3, os dois parâmetros acima são pré-configurados por padrão e podem ser modificados por meio do OSGi QueryEngineSettings.
Mais informações disponíveis em : https://jackrabbit.apache.org/oak/docs/query/query-engine.html#Slow_Queries_and_Read_Limits
O lema da otimização do desempenho da consulta no AEM é:
"Quanto mais restrições, melhor."
Os itens a seguir descrevem ajustes recomendados para garantir o desempenho da consulta. Primeiro, ajuste a consulta, uma atividade menos invasiva e, em seguida, se necessário, ajuste as definições de índice.
O AEM é compatível com os seguintes idiomas de consulta:
O exemplo a seguir usa o Construtor de consultas como sua linguagem de consulta mais comum usada por desenvolvedores do AEM, no entanto, os mesmos princípios são aplicáveis ao JCR-SQL2 e ao XPath.
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 restrição de tipo de nó forçam o AEM a assumir o nt:base
Nodetype, que todos os nós no AEM são um subtipo de, resultando efetivamente em nenhuma restrição de nodetype.
Configuração type=cq:Page
restringe esta consulta a apenas cq:Page
e resolve a consulta para AEM cqPageLucene, limitando os resultados a um subconjunto de nós (somente cq:Page
nós) no AEM.
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 nodetipo pai de cq:Page
. Presumindo jcr:content/contentType=article-page
é aplicado somente a cq:Page
nós por meio do aplicativo personalizado Adobe, essa consulta só retorna cq:Page
nós onde jcr:content/contentType=article-page
. No entanto, esse fluxo é uma restrição abaixo do ideal, pois:
nt:hierarchyNode
(por exemplo, dam:Asset
) adicionando desnecessariamente ao conjunto de resultados potenciais.nt:hierarchyNode
, no entanto, uma vez que existe um índice cq:Page
.Configuração type=cq:Page
restringe esta consulta a apenas cq:Page
e resolve a consulta para AEM cqPageLucene, limitando os resultados a um subconjunto de nós (somente nós cq:Page) no AEM.
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
Alteração da restrição de propriedade de jcr:content/contentType
(um valor personalizado) para a propriedade bem conhecida sling:resourceType
permite que a consulta resolva para o índice de propriedade slingResourceType
que indexa todo o conteúdo por sling:resourceType
.
Os índices de propriedade (em oposição aos índices de propriedade Lucene) são usados melhor quando a consulta não discerne por nodetype e uma única restrição de propriedade domina o conjunto de resultados.
/content/my-site/us/en
sobre /content/my-site
ou /content/dam
sobre /
.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=/content
para path=/content/my-site/us/en
permite que os índices reduzam o número de entradas de índice que devem ser inspecionadas. Quando a consulta pode restringir bem o caminho, além de apenas /content
ou /content/dam
, verifique se o índice evaluatePathRestrictions=true
.
Observação usando evaluatePathRestrictions
aumenta o tamanho do índice.
LIKE
e fn:XXXX
à medida que seus custos são escalonados com o 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 ser avaliada porque nenhum índice pode ser usado se o texto começar com um curinga ("%…'). A condição jcr:contains permite o uso de um índice de texto completo e, portanto, é preferível. É necessário que o Índice de Propriedade Lucene resolvido tenha indexRule para jcr:content/contentType
com analayzed=true
.
Usar funções de consulta como fn:lowercase(..)
pode ser mais difícil de otimizar, pois não há equivalentes mais rápidos (fora de configurações mais complexas e invasivas 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 em potencial.
Esse ajuste é específico do Construtor de consultas e não se aplica a JCR-SQL2 ou XPath.
Uso guessTotal do Construtor de Consulta 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
é uma otimização crítica para consultas do Construtor de consultas.
p.guessTotal=100
instrui o Query Builder a coletar apenas os primeiros 100 resultados. E, para definir um sinalizador booleano indicando se pelo menos mais um resultado existe (mas não quantos mais, já que contar esse número resulta em lentidão). Essa otimização é excelente para casos de uso de paginação ou carregamento infinito, em que apenas um subconjunto de resultados é exibido de forma incremental.
Se a consulta ideal for resolvida como um Índice de propriedade, não há mais nada a ser feito, pois os Índices de propriedade são ajustáveis minimamente.
Caso contrário, a consulta deve ser resolvida para um Índice de propriedades Lucene. Se nenhum índice puder ser resolvido, vá para Criação de um índice.
Conforme necessário, converta a consulta para XPath ou JCR-SQL2.
Consulta do Construtor de consultas
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 a partir da consulta do Construtor de Consultas
/jcr:root/content/my-site/us/en//element(*, cq:Page)[jcr:content/@contentType = 'article-page'] order by jcr:content/@publishDate descending
Forneça o XPath (ou JCR-SQL2) ao Gerador de definição de índice do Oak em https://oakutils.appspot.com/generate/index
para que você possa gerar a definição otimizada do Índice de propriedades Lucene.
Definição de índice de propriedade 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"
Mescle manualmente a definição gerada no Índice de propriedades Lucene existente de forma aditiva. Tenha cuidado para não remover configurações existentes, pois elas podem ser usadas para atender a outras consultas.
/oak:index/cqPageLucene
.Verifique se a consulta não resolve um Índice de Propriedade Lucene existente. Se isso acontecer, consulte a seção acima sobre ajuste e índice existente.
Conforme necessário, converta a consulta para XPath ou JCR-SQL2.
Consulta do Construtor de consultas
type=myApp:Author
property=firstName
property.value=ira
XPath gerado a partir da consulta do Construtor de Consultas
//element(*, myApp:Page)[@firstName = 'ira']
Forneça o XPath (ou JCR-SQL2) ao Gerador de definição de índice do Oak em https://oakutils.appspot.com/generate/index
para que você possa gerar a definição otimizada do Índice de propriedades Lucene.
Definição de índice de propriedade Lucene gerada
- compatVersion = 2
- type = "lucene"
- async = "async"
- jcr:primaryType = oak:QueryIndexDefinition
+ indexRules
+ myApp:AuthorModel
+ properties
+ firstName
- name = "firstName"
- propertyIndex = true
Implante a definição do Índice de propriedade Lucene gerada.
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, trate 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 é resolvida para o índice e se a consulta tem desempenho.
Na implantação inicial desse índice, o AEM preenche o índice com os dados necessários.
Devido à arquitetura de conteúdo flexível do AEM, é difícil prever e garantir que os percursos das estruturas de conteúdo não evoluam ao longo do tempo para serem inaceitavelmente grandes.
Portanto, verifique se os índices atendem a consultas, exceto se a combinação de restrição de caminho e restrição de tipo de nó garantir que menos de 20 nós são percorridos.
Depurador do Construtor de consultas
CRXDE Lite - Ferramenta de consulta
Log do Construtor de consultas
DEBUG @ com.day.cq.search.impl.builder.QueryImpl
Log de execução de consulta do Oak
DEBUG @ org.apache.jackrabbit.oak.query
Configurações de OSGi do mecanismo de consulta do Apache Jackrabbit
NodeCounter JMX Mbean
Gerador de definição de índice Oak emhttps://oakutils.appspot.com/generate/index