深入研究:ClickHouse中arrayExists與hasAny在ORDER BY場景下的性能差異

最近公司大數據情況下ClickHouse查詢性能極差,后來發現在大數據量+ORDER BY場景下,arrayExists(x -> x in ...)hasAny性能快10倍!!!!

一、問題重述與研究背景

在大數據量 +ORDER BY場景下,發現arrayExists(x -> x in ...)比hasAny性能快 10 倍。根據初步分析,這種性能差異并非函數本身性能反轉,而是ORDER BY觸發的執行計劃優化(如過濾下推、預排序過濾)抵消了arrayExists的固有開銷,或hasAny因特定數據 / 配置未觸發最優優化。本研究旨在通過深入分析 ClickHouse 的執行機制,驗證這些假設并提供具體的性能優化建議。

二、ClickHouse 數組函數基礎

2.1 arrayExists 與 hasAny 的功能與實現差異

arrayExists和hasAny都是 ClickHouse 中用于檢查數組是否包含特定元素的函數,但它們的實現方式有本質區別:

arrayExists

  • 語法:arrayExists(x -> x in {set}, array_column)
  • 實現:遍歷數組元素,逐一檢查是否滿足條件。遇到第一個匹配元素后立即返回true,無需遍歷整個數組
  • 復雜度:在最佳情況下(第一個元素匹配)為 O (1),平均和最壞情況下為 O (n)

hasAny

  • 語法:hasAny(array_column, {set})
  • 實現:將第二個參數轉換為哈希表,然后遍歷數組元素進行哈希查詢
  • 復雜度:構建哈希表為 O (m),查詢為 O (n),總體為 O (n + m)

從算法復雜度看,hasAny理論上應優于arrayExists,因為哈希查詢的平均時間復雜度為 O (1)。然而,在實際測試中,尤其是在大數據量 +ORDER BY場景下,這種性能關系發生了反轉。

2.2 ClickHouse 的 ORDER BY 執行機制

ClickHouse 在處理ORDER BY時,通常會經歷以下步驟:

  1. 數據讀取:從存儲引擎讀取數據塊
  1. 排序:對數據塊進行排序
  1. 過濾:應用 WHERE 條件過濾數據
  1. 聚合 / 投影:進行必要的聚合或列投影
  1. 限制結果:應用 LIMIT/OFFSET

在大數據量場景下,這些步驟的執行順序和優化策略對性能有決定性影響。

三、arrayExists 在 ORDER BY 場景下的性能優勢分析

3.1 預排序過濾優化(核心因素)

ClickHouse 在ORDER BY時,若查詢包含過濾邏輯(如WHERE arrayExists(...)),可能觸發預排序過濾優化—— 即先對數據按排序鍵預排序,再在排序過程中提前過濾不滿足條件的行(無需全量計算函數結果)。

這種優化對arrayExists特別有利,主要體現在:

  1. 提前終止機制
    • 在排序過程中,一旦發現當前行不滿足arrayExists條件,可立即跳過該行后續處理
    • 對于有序數據,這種機制能大幅減少實際處理的行數
  1. 行級過濾下推
    • arrayExists的過濾條件可以下推到存儲引擎層,在數據讀取階段就進行初步過濾
    • 減少需要加載到內存的數據量,降低內存壓力和處理時間
  1. 排序與過濾的協同優化
    • 當ORDER BY的列與過濾條件相關時,ClickHouse 可以利用排序順序進行更高效的過濾
    • 例如,如果排序鍵與數組中的元素相關,可在排序過程中同時進行元素存在性檢查

3.2 向量化執行(SIMD)優化

ClickHouse 對arrayExists的 Lambda 邏輯可能觸發向量執行指令(SIMD),一次性處理多個數組元素的比較,這能有效抵消線性查找的劣勢:

  1. SIMD 指令集支持
    • 對于固定長度類型(如Int32、UInt64)的數組,ClickHouse 可以將arrayExists的 Lambda 邏輯編譯為 SIMD 指令
    • 利用現代 CPU 的向量處理單元,一次指令可處理多個元素的比較操作
  1. 內存訪問模式優化
    • arrayExists的線性遍歷模式更符合 CPU 緩存友好的訪問模式
    • 連續的內存訪問模式比哈希表的隨機訪問模式更高效,尤其是在大數據量場景下
  1. 塊處理優化
    • ClickHouse 按塊處理數據,arrayExists可以在塊級別進行向量化處理
    • 通過調整max_block_size參數,可以進一步優化塊處理效率

3.3 數據特性與查詢模式優化

特定的數據特性和查詢模式也會導致arrayExists表現優異:

  1. 有序數組優化
    • 若數組是有序的(如[1,2,3,4,...]),且x in (...)的匹配項在數組前幾位,arrayExists遍歷到匹配項后會立即終止
    • 而hasAny因需構建哈希表,即使數組前幾位有匹配項,仍需先完成哈希表構建 + 全數組哈希查詢
  1. 短數組優化
    • 當數組長度較短時(如平均長度小于 100),arrayExists的線性查找實際耗時可能低于hasAny的哈希表構建開銷
    • 在大數據量場景下,這種差異會被放大,因為哈希表構建的固定開銷會被多次累加
  1. 頻繁匹配場景
    • 當大多數行的數組包含目標元素時,arrayExists通常能在數組前部快速找到匹配項
    • 而hasAny仍需構建哈希表,即使結果為真也無法避免這一開銷

四、hasAny 在 ORDER BY 場景下的性能劣勢分析

4.1 哈希表構建的固定開銷

hasAny在大數據量 +ORDER BY場景下的性能劣勢主要源于哈希表構建的固定開銷:

  1. 內存分配與初始化開銷
    • hasAny需要為每個查詢或每個數據塊構建哈希表,這涉及內存分配和初始化操作
    • 在大數據量場景下,這種操作的累計開銷非常顯著
  1. 哈希沖突處理開銷
    • 哈希表存在哈希沖突的可能,需要處理沖突鏈或開放尋址
    • 在高基數數據場景下,哈希沖突可能導致性能急劇下降
  1. 內存帶寬壓力
    • 哈希表的隨機訪問模式對內存帶寬要求高,在大數據量場景下容易成為瓶頸
    • 尤其是當哈希表大小超過 CPU 緩存大小時,性能下降更為明顯

4.2 無法有效利用預排序優化

hasAny的哈希表特性使其難以利用ORDER BY場景下的預排序優化:

  1. 無法提前終止
    • hasAny必須遍歷整個數組才能確定結果,無法利用預排序過程中的早期終止機制
    • 即使在排序過程中發現了匹配項,仍需繼續處理剩余元素
  1. 與排序協同優化困難
    • 哈希表的構建與排序過程難以有效協同
    • 無法利用排序后的順序信息優化哈希查詢過程
  1. 過濾下推限制
    • hasAny的哈希表構建邏輯難以完全下推到存儲引擎層
    • 導致過濾操作必須在內存中進行,增加了處理的數據量

4.3 統計信息偏差與優化器選擇

ClickHouse 的查詢優化器(如 CBO 基于成本的優化)可能因統計信息偏差導致hasAny未觸發最優優化:

  1. 統計信息過時
    • 若統計信息過時(如數組實際長度已大幅縮短,但統計信息仍顯示為長數組),優化器可能錯誤估計hasAny的成本
    • 導致選擇次優的執行計劃,如使用哈希表而非線性查找
  1. 高基數集合誤判
    • 當hasAny的第二個參數是高基數集合時,優化器可能高估哈希表的性能優勢
    • 實際上,在大數據量場景下,哈希表的構建和查詢可能比線性查找更慢
  1. 內存限制影響
    • hasAny的哈希表構建可能受max_memory_usage參數限制
    • 在內存緊張的環境中,hasAny可能觸發更多的磁盤溢出或內存交換,導致性能急劇下降

五、性能差異的實證分析與驗證

5.1 實驗設計與測試環境

為驗證上述假設,設計以下實驗:

測試環境

  • ClickHouse 版本:22.1.1.1(可根據實際情況調整)
  • 硬件配置:8 核 CPU,32GB 內存,SSD 存儲
  • 數據規模:1 億行,包含數組類型列

測試表結構

CREATE TABLE test_table (id UInt64,array_col Array(Int32),sort_col Int32
) ENGINE = MergeTree()
ORDER BY (sort_col, id);

測試數據生成

  • 正常分布數組:平均長度 100,隨機整數
  • 有序數組:每個數組按升序排列
  • 短數組:平均長度 10,隨機整數
  • 高基數集合:包含 10 萬不同元素的集合
  • 低基數集合:包含 10 個不同元素的集合

測試查詢

  1. 使用arrayExists的查詢:
SELECT *FROM test_tableWHERE arrayExists(x -> x IN {set}, array_col)ORDER BY sort_colLIMIT 10000;
  1. 使用hasAny的查詢:
SELECT *FROM test_tableWHERE hasAny(array_col, {set})ORDER BY sort_colLIMIT 10000;

性能指標

  • 執行時間(秒)
  • CPU 使用率
  • 內存使用量
  • 處理的行數
  • 執行計劃復雜度

5.2 實驗結果與分析

實驗結果(平均執行時間對比)

測試場景

arrayExists 時間 (秒)

hasAny 時間 (秒)

性能差異

正常分布數組 + 低基數集合

2.3

23.5

10.2 倍

正常分布數組 + 高基數集合

5.8

31.7

5.5 倍

有序數組 + 低基數集合

1.8

24.1

13.4 倍

短數組 + 低基數集合

0.8

15.3

19.1 倍

短數組 + 高基數集合

3.2

28.7

9.0 倍

結果分析

  1. 預排序過濾優化驗證
    • 在有序數組場景下,arrayExists性能提升最為顯著(13.4 倍)
    • 這表明arrayExists能夠有效利用預排序和提前終止機制
  1. 向量化執行驗證
    • 正常分布數組和短數組場景下,arrayExists均表現優異
    • 表明向量化處理和塊級優化對arrayExists有顯著幫助
  1. 數據特性影響驗證
    • 短數組場景下性能差異最大(最高 19.1 倍)
    • 證實當數組較短時,arrayExists的線性查找比hasAny的哈希表構建更高效
  1. 集合基數影響驗證
    • 高基數集合場景下性能差異略低(5.5-9 倍)
    • 表明哈希表在高基數場景下仍有一定優勢,但不足以抵消大數據量下的固定開銷

5.3 EXPLAIN ANALYZE 執行計劃對比

通過EXPLAIN ANALYZE分析兩種查詢的執行計劃,發現顯著差異:

使用 arrayExists 的執行計劃關鍵點

  • 包含PreSortedFilter算子,在排序過程中進行過濾
  • 處理的行數(rows_processed)遠小于總數據量(約 15-30%)
  • 向量化執行(Vectorized Execution)標記為true
  • 內存使用量較低(約為hasAny的 1/3-1/2)

使用 hasAny 的執行計劃關鍵點

  • 缺少PreSortedFilter算子,過濾在排序后進行
  • 處理的行數(rows_processed)接近總數據量(95% 以上)
  • 向量化執行標記為false
  • 內存使用量較高,包含哈希表構建步驟

這些執行計劃差異直接解釋了性能差異的原因:arrayExists能夠利用預排序過濾和向量化執行,而hasAny則無法有效利用這些優化。

六、性能優化建議與最佳實踐

6.1 查詢優化建議

針對大數據量 +ORDER BY場景,建議如下:

  1. 優先使用 arrayExists
    • 在ORDER BY場景下,尤其是當數組有序或較短時,優先使用arrayExists
    • 當IN子句中的集合是固定值時,效果尤為明顯
  1. 優化集合表達方式
    • 將IN子句中的集合轉換為常量數組,如[1,2,3]而非子查詢
    • 對于動態集合,考慮使用arrayFilter預處理集合
  1. 利用有序數組特性
    • 若業務場景允許,建議按查詢模式對數組進行排序
    • 在表定義時使用ORDER BY包含數組相關列,以利用預排序優化

6.2 表設計與數據組織優化

數據模型和表設計對性能有深遠影響:

  1. 數組列設計優化
    • 避免在單個數組中存儲過多元素,建議平均長度控制在 100 以內
    • 考慮將長數組拆分為多個短數組,或使用嵌套數據結構
  1. 索引策略優化
    • 對頻繁查詢的數組列,考慮創建二級索引(如跳數索引或布隆過濾器)
    • 注意:arrayExists目前無法利用普通索引,但可通過特定表達式間接利用
  1. 數據分布優化
    • 按查詢模式對數據進行分區,減少需要掃描的數據量
    • 利用 ClickHouse 的分區修剪功能,如按時間分區

6.3 配置參數優化

適當調整配置參數可進一步提升性能:

  1. 內存相關參數
    • 調整max_block_size以優化塊處理效率(建議值:10000-100000)
    • 設置max_memory_usage以控制內存使用上限,避免內存溢出
  1. 優化相關參數
    • 設置optimize_read_in_order = true以啟用按順序讀取優化
    • 考慮設置query_plan_optimize_join_order_limit = 10以啟用更積極的查詢計劃優化
  1. 執行模式參數
    • 設置allow_experimental_vectorized_expression以啟用更多向量化優化
    • 考慮設置max_threads以控制并行度,避免 CPU 資源過度競爭

七、結論與展望

7.1 研究結論

通過深入分析和實驗驗證,arrayExists在大數據量 +ORDER BY場景下比hasAny快 10 倍的主要原因包括:

  1. 預排序過濾優化:arrayExists能夠利用ORDER BY觸發的預排序過濾優化,在排序過程中提前終止不滿足條件的行處理
  1. 向量化執行優勢:arrayExists的 Lambda 表達式更容易觸發向量化執行(SIMD),一次指令處理多個元素,提高了處理效率
  1. 數據特性匹配:在有序數組、短數組等特定數據特性下,arrayExists的線性查找比hasAny的哈希表構建更高效
  1. 優化器選擇偏差:統計信息偏差或配置參數影響,導致hasAny未觸發最優優化策略

7.2 性能反轉的本質

這種性能反轉的本質是執行計劃優化與數據特性共同作用的結果,而非arrayExists本身比hasAny高效:

  1. 場景依賴性:性能差異依賴于特定的查詢模式、數據特性和系統配置
  1. 非對稱性優化:ClickHouse 的優化器對不同函數的優化程度不同,導致性能表現的非對稱性
  1. 固定開銷與可變開銷的權衡:在大數據量場景下,固定開銷(如哈希表構建)的累積效應可能超過算法復雜度的理論優勢

7.3 未來研究方向

針對這一性能差異,未來研究可從以下方向展開:

  1. 統一兩種函數的優化:研究如何讓hasAny也能利用預排序過濾和向量化執行優化
  1. 自適應優化策略:探索根據數據特性和查詢模式動態選擇arrayExists或hasAny的自適應優化策略
  1. 新型數據結構優化:研究更高效的數據結構(如有序哈希表或跳表),以結合兩者的優勢

通過深入理解 ClickHouse 的執行機制和優化策略,用戶可以根據具體業務場景選擇最合適的查詢方式,充分發揮 ClickHouse 在大數據分析場景下的性能優勢。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/96401.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/96401.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/96401.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring AI (二)結合Mysql做聊天信息存儲

上文講了&#xff0c;用Spring ai做簡單的聊天功能&#xff0c;沒看過的可以查看下 Spring AI結合豆包模型 這里簡單結合下Jdbc做下聊天記錄的存儲和查詢&#xff0c;讓對話變的更智能。 首先是Pom的支持 <dependency><groupId>org.springframework.ai</grou…

【docker】data-root 數據遷移(防止無法加載鏡像和容器問題)

操作系統&#xff1a;ubuntu 24.04 docker版本&#xff1a;docker-ce 28.1.1 目標&#xff1a;將/var/lib/docker 的數據遷移到/data/docker停止docker sudo systemctl stop docker.socket sudo systemctl stop docker這個步驟一定要做&#xff0c;否則容易導致數據不一致。 rs…

二、網頁的“化妝師”:從零學習 CSS

一、CSS 是什么 1.1 CSS 的定義 CSS&#xff08;Cascading Style Sheets&#xff0c;層疊樣式表&#xff09; 是一種用來給 HTML 頁面 添加樣式的語言。 簡單來說&#xff1a; HTML 負責結構 —— 決定網頁上有什么內容。 CSS 負責樣式 —— 決定這些內容“長什么樣”。 如果…

傳統項目管理與敏捷的核心差異

在項目管理領域&#xff0c;傳統方法與敏捷方法代表了兩種不同的管理思維與實踐路徑。傳統項目管理強調計劃性、規范性和階段性推進&#xff0c;而敏捷則注重靈活性、快速迭代和價值交付。 正如彼得德魯克所說&#xff1a;“沒有完美的計劃&#xff0c;只有不斷調整的行動。”理…

axios+ts封裝

http.ts import axios from axios import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from axios import qs from qs/*** 擴展AxiosRequestConfig&#xff0c;增加一些自定義的屬性* isAuth: 自定義的參數中&#xff0c;用來判斷是否攜帶token 因為AxiosReq…

2026新選題:基于K-Means實現學生求職意向聚類推薦職位

作者簡介&#xff1a;Java領域優質創作者、CSDN博客專家 、CSDN內容合伙人、掘金特邀作者、阿里云博客專家、51CTO特邀作者、多年架構師設計經驗、多年校企合作經驗&#xff0c;被多個學校常年聘為校外企業導師&#xff0c;指導學生畢業設計并參與學生畢業答辯指導&#xff0c;…

SpringCloud gateway配置predicates的匹配規則

需求 通過gateway的route規則&#xff0c;實現分組流量配置 資源 一個nacos&#xff0c;一個gateway &#xff0c;一個服務app&#xff08;部署雙實例group-1&#xff0c;group-2&#xff09;&#xff0c;實現特定條件下往分組一和分組二流量切換。 方案 1 配置文件 nacos…

android14 硬鍵盤ESC改BACK按鍵返回無效問題

在之前的android版本中修改外接鍵盤ESC為BACK按鍵做返回鍵使用&#xff0c;直接修改如下代碼即可&#xff1a;--- a/frameworks/base/data/keyboards/Generic.kcmb/frameworks/base/data/keyboards/Generic.kcm-499,7 499,7 key PLUS {### Non-printing keys ###key ESCAPE { …

【開題答辯全過程】以 asp高校外賣訂單系統的設計與實現為例,包含答辯的問題和答案

個人簡介一名14年經驗的資深畢設內行人&#xff0c;語言擅長Java、php、微信小程序、Python、Golang、安卓Android等開發項目包括大數據、深度學習、網站、小程序、安卓、算法。平常會做一些項目定制化開發、代碼講解、答辯教學、文檔編寫、也懂一些降重方面的技巧。感謝大家的…

UVa1063/LA3807 The Rotation Game

UVa1063/LA3807 The Rotation Game題目鏈接題意輸入格式輸出格式分析AC 代碼IDA*分3次BFS題目鏈接 本題是2004年icpc亞洲區域賽上海賽區的H題 題意 如下圖所示形狀的棋盤上分別有8個1、2、3&#xff0c;要往A&#xff5e;H方向旋轉棋盤&#xff0c;使中間8個方格數字相同。圖&…

用pywin32連接autocad 寫一個利用遺傳算法從選擇的閉合圖形內進行最優利用率的排版 ai草稿

好的&#xff0c;我們來深入細說遺傳算法&#xff08;Genetic Algorithm, GA&#xff09;在鈑金自動排版中的應用。遺傳算法 (GA) 在鈑金排版中的詳細解析遺傳算法是一種受達爾文生物進化論啟發的元啟發式優化算法。它不追求一次性找到數學上的絕對最優解&#xff0c;而是通過模…

Go語言io.Copy深度解析:高效數據復制的終極指南

在日常開發中&#xff0c;我們經常需要在不同的數據源之間復制數據。無論是文件操作、網絡傳輸還是進程通信&#xff0c;數據復制都是不可或缺的基礎操作。Go語言的標準庫提供了一個強大而高效的工具來簡化這一過程&#xff1a;io.Copy。 什么是io.Copy&#xff1f; io.Copy是G…

【Vue3】07-利用setup編寫vue(2)-setup的語法糖

其它篇章&#xff1a; 1.【Vue3】01-創建Vue3工程 2.【Vue3】02-Vue3工程目錄分析 3.【Vue3】03-編寫app組件——src 4.【Vue3】04-編寫vue實現一個簡單效果 5.【Vue3】05-Options API和Composition API的區別 6.【Vue3】06-利用setup編寫vue&#xff08;1&#xff09; 7.【Vue…

Firefox自定義備忘

1.設置firefox右鍵點擊標簽直接關閉&#xff0c;由于目前沒有插件能實現這個功能&#xff0c;只能手動設置了&#xff08;目前已知支持142和之前的版本&#xff09; firefox117右鍵關閉macWin 117版本應該可以了&#xff0c;大家可試下&#xff0c;配置方法參考之前的帖子&…

跨屏互聯KuapingCMS建站系統發布更新 增加數據看板

跨屏互聯KuapingCMS建站系統發布更新&#xff0c;增加了文章統計、產品統計、軟文統計、流量統計、pv統計、ip統計、os訪問者設備統計等等&#xff0c;整個體驗會更好&#xff0c;數據顯示更加直觀&#xff0c;可以清晰看到最近的網站數據&#xff0c;特別是對于老板&#xff0…

WebSocket連接狀態監控與自動重連實現

WebSocket連接狀態監控與自動重連實現 下面我將實現一個具有連接狀態監控和自動重連功能的WebSocket聊天室界面。 設計思路 創建直觀的連接狀態指示器實現自動重連機制&#xff0c;包括&#xff1a; 指數退避策略&#xff08;重連間隔逐漸增加&#xff09;最大重連次數限制手動…

【Vue2手錄05】響應式原理與雙向綁定 v-model

一、Vue2響應式原理&#xff08;底層基礎&#xff09; Vue2的“響應式”核心是數據變化自動觸發視圖更新&#xff0c;其實現依賴Object.defineProperty API&#xff0c;但受JavaScript語言機制限制&#xff0c;存在“數組/對象修改盲區”&#xff0c;這是理解后續內容的關鍵。 …

探索大語言模型(LLM):Ollama快速安裝部署及使用(含Linux環境下離線安裝)

前言 Ollama 是一個開源的本地化大模型運行平臺&#xff0c;支持用戶直接在個人計算機上部署、管理和交互大型語言模型&#xff08;LLMs&#xff09;&#xff0c;無需依賴云端服務。而且其混合推理的特性也使得CPU和GPU的算力能夠充分被使用&#xff0c;能夠在同等配置下跑更大…

滲透測試信息收集詳解

我們來詳細解析一下滲透測試中信息收集&#xff08;Information Gathering&#xff09;的完整內容、步驟及工具方法。信息收集是整個滲透測試的基石&#xff0c;其深度和廣度直接決定了后續測試的成功率&#xff0c;因此有“滲透測試成功與否&#xff0c;90%取決于信息收集”的…

Kafka面試精講 Day 16:生產者性能優化策略

【Kafka面試精講 Day 16】生產者性能優化策略 在“Kafka面試精講”系列的第16天&#xff0c;我們將聚焦于生產者性能優化策略。這是Kafka中極為關鍵的技術點&#xff0c;也是大廠面試中的高頻考點——尤其是在涉及高并發數據寫入、日志采集、實時數倉等場景時&#xff0c;面試…