疑難排解慢速查詢 troubleshooting-slow-queries

CAUTION
AEM 6.4已結束延伸支援,本檔案不再更新。 如需詳細資訊,請參閱 技術支援期. 尋找支援的版本 此處.

查詢分類速度緩慢 slow-query-classifications

AEM中有3個主要的慢速查詢分類,依嚴重性列出:

  1. 無索引查詢

    • 查詢 not 解析為索引並遍歷JCR的內容以收集結果
  2. 限制不足(或限定範圍)的查詢

    • 解析為索引的查詢,但必須遍歷所有索引條目以收集結果
  3. 大型結果集查詢

    • 傳回大量結果的查詢

前2個查詢分類(無索引且限制不良)速度緩慢,因為這會強制Oak查詢引擎檢查每個 潛在 結果(內容節點或索引條目),以標識屬於 實際 結果集。

檢查每個潛在結果的行為稱為「遍歷」。

由於必須檢查每個潛在結果,因此確定實際結果集的成本與電位結果的數目呈線性增長。

添加查詢限制和調整索引允許以優化格式儲存索引資料,提供快速結果檢索,並且減少或消除對潛在結果集的線性檢查的需要。

在AEM 6.3中,依預設,當到達100,000的周遊時,查詢會失敗並擲回例外狀況。 AEM 6.3之前的AEM版本預設不存在此限制,但可透過Apache Jackrabbit查詢引擎設定OSGi設定和QueryEngineSettings JMX Bean(屬性LimitReads)設定。

檢測無索引查詢 detecting-index-less-queries

開發期間 during-development

說明 all 查詢,並確保其查詢計畫不包含 /*橫貫 解釋。 遍歷查詢計畫的示例:

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

部署後 post-deployment

  • 監視 error.log 對於無索引遍歷查詢:

    • *INFO* org.apache.jackrabbit.oak.query.QueryImpl Traversal query (query without index) ... ; consider creating and index
    • 只有在沒有可用索引且查詢可能遍歷許多節點時,才會記錄此消息。 如果索引可用,則不會記錄消息,但遍歷的量很小,因此速度很快。
  • 造訪AEM 查詢效能 操作控制台和 說明 查詢查找遍歷或沒有索引查詢解釋的速度較慢。

檢測限制不良的查詢 detecting-poorly-restricted-queries

開發期間 during-development-1

說明所有查詢,並確保它們解析為符合查詢屬性限制的調整索引。

  • 理想的查詢計畫覆蓋範圍 indexRules ,並且至少對於查詢中最緊的屬性限制。
  • 對排序結果進行查詢時,應解析為具有按設定的屬性排序的索引規則的Lucene屬性索引 orderable=true.

例如,預設 cqPageLucene 沒有的索引規則 jcr:content/cq:tags for-example-the-default-cqpagelucene-does-not-have-an-index-rule-for-jcr-content-cq-tags

新增cq:tags索引規則之前

  • cq:tags索引規則

    • 不存在
  • 查詢產生器查詢

    code language-none
    type=cq:Page
     property=jcr:content/cq:tags
     property.value=my:tag
    
  • 查詢計畫

    • [cq:Page] as [a] /* lucene:cqPageLucene(https://experienceleague.adobe.com/oak:index/cqPageLucene?lang=zh-Hant) *:* where [a].[jcr:content/cq:tags] = 'my:tag' */

此查詢解析到 cqPageLucene 索引,但因為沒有屬性索引規則 jcr:contentcq:tags,在評估此限制時, cqPageLucene 檢查索引以確定匹配項。 這表示如果索引包含100萬 cq:Page 然後檢查100萬條記錄以確定結果集。

新增cq:tags索引規則後

  • cq:tags索引規則

    code language-none
    /oak:index/cqPageLucene/indexRules/cq:Page/properties/cqTags
     @name=jcr:content/cq:tags
     @propertyIndex=true
    
  • 查詢產生器查詢

    code language-none
    type=cq:Page
     property=jcr:content/cq:tags
     property.value=myTagNamespace:myTag
    
  • 查詢計畫

    • [cq:Page] as [a] /* lucene:cqPageLucene(https://experienceleague.adobe.com/oak:index/cqPageLucene?lang=zh-Hant) jcr:content/cq:tags:my:tag where [a].[jcr:content/cq:tags] = 'my:tag' */

jcr:content/cq:tagscqPageLucene 索引允許 cq:tags 以最佳方式儲存的資料。

若查詢包含 jcr:content/cq:tags 執行限制時,索引可依值查詢結果。 這意味著如果100 cq:Page 節點 myTagNamespace:myTag 作為值,僅返回這100個結果,而其他999,000則從限制檢查中排除,使效能提高10,000倍。

當然,進一步的查詢限制會減少符合條件的結果集,並進一步優化查詢優化。

同樣地,不使用 cq:tags 屬性,甚至具有 cq:tags 執行效果不佳,因為索引的結果會傳回所有全文相符項目。 cq:tags上的限制會在之後篩選。

索引後篩選的另一個原因是存取控制清單,在開發期間經常會遺漏。 嘗試確定查詢未返回用戶可能無法訪問的路徑。 這通常可以透過更好的內容結構以及提供查詢的相關路徑限制來完成。

要識別Lucene索引是否傳回大量結果以傳回非常小的子集(作為查詢結果),有一種很實用的方法是為 org.apache.jackrabbit.oak.plugins.index.lucene.LucenePropertyIndex 並查看從索引中載入的文檔數。 最終結果的數量與載入的文檔的數量之間不應不成比例。 如需詳細資訊,請參閱 記錄.

部署後 post-deployment-1

  • 監視 error.log 對於遍歷查詢:

    • *WARN* org.apache.jackrabbit.oak.spi.query.Cursors$TraversingCursor Traversed ### nodes ... consider creating an index or changing the query
  • 造訪AEM 查詢效能 操作控制台和 說明 查詢查找查詢計畫時速度緩慢,無法將查詢屬性限制解析為索引屬性規則。

檢測大型結果集查詢 detecting-large-result-set-queries

開發期間 during-development-2

為oak.queryLimitInMemory設定低臨界值(例如 10000)和oak.queryLimitReads(例如 5000),並在點擊「查詢讀取的節點數超過x個……」的UnsupportedOperationException時,優化昂貴的查詢

這有助於避免資源密集型查詢(即。 不受任何索引的支援或受覆蓋索引較少的支援)。 例如,讀取1M個節點的查詢將導致大量IO,並對整體應用程式效能產生負面影響。 因此,任何因上述限制而失敗的查詢都應加以分析和最佳化。

部署後 post-deployment-2

  • 監視日誌中是否有觸發大節點遍歷或大堆記憶體消耗的查詢:

    • *WARN* ... java.lang.UnsupportedOperationException: The query read or traversed more than 100000 nodes. To avoid affecting other tasks, processing was stopped.
    • 優化查詢以減少已遍歷的節點數
  • 監視日誌中觸發大堆記憶體消耗的查詢:

    • *WARN* ... java.lang.UnsupportedOperationException: The query read more than 500000 nodes in memory. To avoid running out of memory, processing was stopped
    • 優化查詢以減少堆記憶體消耗

對於AEM 6.0 - 6.2版,您可以透過AEM啟動指令碼中的JVM參數來調整節點周遊臨界值,以防止大型查詢超出環境負載。 建議的值為:

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

在AEM 6.3中,上述2個參數預設已預先設定,並可透過OSGi QueryEngineSettings修改。

如需詳細資訊,請參閱: https://jackrabbit.apache.org/oak/docs/query/query-engine.html#Slow_Queries_and_Read_Limits

查詢效能調整 query-performance-tuning

AEM中查詢效能最佳化的格言為:

「限制越多越好。」

以下概述了為確保查詢效能而建議的調整。 首先調整查詢(不那麼引人注目的活動),然後根據需要調整索引定義。

調整查詢語句 adjusting-the-query-statement

AEM支援下列查詢語言:

  • 查詢產生器
  • JCR-SQL2
  • XPath

下列範例使用查詢產生器,因為這是AEM開發人員最常使用的查詢語言,但JCR-SQL2和XPath也適用相同的原則。

  1. 添加nodetype限制,使查詢解析到現有Lucene屬性索引。

    • 未優化的查詢

      code language-none
       property=jcr:content/contentType
       property.value=article-page
      
    • 最佳化查詢

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

    缺少nodetype限制的查詢會強制AEM採用 nt:base nodetype,AEM中的每個節點都是的子類型,因此有效地沒有nodetype限制。

    設定 type=cq:Page 僅限此查詢 cq:Page 節點,並將查詢解析為AEM cqPageLucene,將結果限制為節點子集(僅限於 cq:Page 節點)。

  2. 調整查詢的nodetype限制,使查詢解析為現有Lucene屬性索引。

    • 未優化的查詢

      code language-none
      type=nt:hierarchyNode
      property=jcr:content/contentType
      property.value=article-page
      
    • 最佳化查詢

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

    nt:hierarchyNode 是的父節點類型 cq:Page,並假設 jcr:content/contentType=article-page 僅套用至 cq:Page 透過自訂應用程式傳回的節點,此查詢只會傳回 cq:Page 節點 jcr:content/contentType=article-page. 這是次優限制,因為:

    • 其他節點繼承自 nt:hierarchyNode (例如 dam:Asset)會不必要地新增至可能的結果集。
    • 沒有AEM提供的索引 nt:hierarchyNode,但由於 cq:Page.

    設定 type=cq:Page 僅限此查詢 cq:Page 節點,並將查詢解析為AEM cqPageLucene,將結果限制為AEM中的節點子集(僅cq:Page節點)。

  3. 或者,調整屬性限制,使查詢解析為現有的屬性索引。

    • 未優化的查詢

      code language-none
        property=jcr:content/contentType
        property.value=article-page
      
    • 最佳化查詢

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

    將屬性限制從 jcr:content/contentType (自訂值)至已知屬性 sling:resourceType 可讓查詢解析為屬性索引 slingResourceType 對所有內容進行索引 sling:resourceType.

    當查詢不能通過nodetype進行辨識,並且單個屬性限制主導結果集時,最好使用屬性索引(與Lucene屬性索引相對)。

  4. 將最緊的路徑限制添加到查詢。 例如,偏好 /content/my-site/us/en over /content/my-site,或 /content/dam over /.

    • 未優化的查詢

      code language-none
      type=cq:Page
      path=/content
      property=jcr:content/contentType
      property.value=article-page
      
    • 最佳化查詢

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

    將路徑限制範圍從 path=/contentto path=/content/my-site/us/en 允許索引減少需要檢查的索引條目數。 當查詢可以很好地限制路徑時, /content/content/dam,確保索引具有 evaluatePathRestrictions=true.

    附註使用 evaluatePathRestrictions 增加索引大小。

  5. 如有可能,請避免查詢函式/操作超調如下: LIKEfn:XXXX 因為其成本隨著限制結果的數量而增加。

    • 未優化的查詢

      code language-none
      type=cq:Page
      property=jcr:content/contentType
      property.operation=like
      property.value=%article%
      
    • 最佳化查詢

      code language-none
      type=cq:Page
      fulltext=article
      fulltext.relPath=jcr:content/contentType
      

    LIKE條件評估速度緩慢,因為如果文字以萬用字元("%。…')開頭,則無法使用索引。 jcr:contains條件允許使用全文索引,因此是推薦條件。 這要求解析的Lucene屬性索引具有的indexRule jcr:content/contentType with analayzed=true.

    使用查詢函式,如 fn:lowercase(..) 可能更難進行優化,因為沒有更快的等效值(除了更複雜且更突出的索引分析器配置外)。 最好找出其他範圍界定限制,以改善整體查詢效能,要求函式對盡可能小的潛在結果集進行操作。

  6. 此調整專用於查詢生成器,不適用於JCR-SQL2或XPath。

    使用 查詢產生器的guessTotal 當需要完整的結果​ ​不立即。

    • 未優化的查詢

      code language-none
      type=cq:Page
      path=/content
      
    • 最佳化查詢

      code language-none
      type=cq:Page
      path=/content
      p.guessTotal=100
      

    若是查詢執行速度快但結果數量大的情況,請參閱。 guessTotal 是查詢產生器查詢的重要最佳化。

    p.guessTotal=100 指示查詢產生器僅收集前100個結果,並設定布林值標幟,指出是否至少存在一個其他結果(但不存在多少個結果),因為計算此數字會導致速度緩慢。 此最佳化優於分頁或無限載入使用案例,其中只會逐步顯示結果的子集。

現有索引調整 existing-index-tuning

  1. 如果最佳查詢解析為屬性索引,則沒有其他任何可做的,因為屬性索引可調性最低。

  2. 否則,查詢應解析為Lucene屬性索引。 如果無法解析索引,請跳到「建立新索引」。

  3. 視需要將查詢轉換為XPath或JCR-SQL2。

    • 查詢產生器查詢

      code language-none
      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

      code language-none
      /jcr:root/content/my-site/us/en//element(*, cq:Page)[jcr:content/@contentType = 'article-page'] order by jcr:content/@publishDate descending
      
  4. 將XPath(或JCR-SQL2)提供給 Oak Index Definition Generator 生成優化的Lucene屬性索引定義。

    生成的Lucene屬性索引定義

    code language-xml
    - 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. 以添加方式手動將生成的定義合併到現有Lucene屬性索引中。 請小心不要刪除現有配置,因為它們可能用於滿足其他查詢。

    1. 找出涵蓋cq:Page的現有Lucene屬性索引(使用索引管理器)。 在這種情況下, /oak:index/cqPageLucene.
    2. 識別最佳化索引定義(步驟#4)與現有索引(https://experienceleague.adobe.com/oak:index/cqPageLucene?lang=zh-Hant)之間的設定差值,並將最佳化索引中遺漏的設定新增至現有索引定義。
    3. 根據AEM重新索引最佳實務,會根據現有內容是否會受此索引組態變更影響,依序重新整理或重新索引。

建立新索引 create-a-new-index

  1. 驗證查詢未解析為現有Lucene屬性索引。 如果有,請參閱上節中關於優化和現有索引的部分。

  2. 視需要將查詢轉換為XPath或JCR-SQL2。

    • 查詢產生器查詢

      code language-none
      type=myApp:Author
      property=firstName
      property.value=ira
      
    • 從查詢生成器查詢生成的XPath

      code language-none
      //element(*, myApp:Page)[@firstName = 'ira']
      
  3. 將XPath(或JCR-SQL2)提供給 Oak Index Definition Generator 生成優化的Lucene屬性索引定義。

    生成的Lucene屬性索引定義

    code language-xml
    - compatVersion = 2
    - type = "lucene"
    - async = "async"
    - jcr:primaryType = oak:QueryIndexDefinition
        + indexRules
        + myApp:AuthorModel
            + properties
            + firstName
                - name = "firstName"
                - propertyIndex = true
    
  4. 部署生成的Lucene屬性索引定義。

    將Oak Index Definition Generator提供之新索引的XML定義新增至AEM專案,以管理Oak索引定義(請記住,將Oak索引定義視為程式碼,因為程式碼取決於這些定義)。

    按照通常的AEM軟體開發生命週期部署並測試新索引,並驗證查詢解析為索引且查詢效能良好。

    初始部署此索引後,AEM會將必要資料填入索引。

無索引和遍歷查詢何時可以? when-index-less-and-traversal-queries-are-ok

由於AEM有彈性的內容架構,很難預測並確保內容結構的周遊性不會隨著時間而演變為無法接受的大。

因此,確保索引滿足查詢,除非路徑限制和nodetype限制的組合保證 橫貫的節點不到20個。

查詢開發工具 query-development-tools

Adobe支援 adobe-supported

支援的社群 community-supported

recommendation-more-help
2315f3f5-cb4a-4530-9999-30c8319c520e