ClickHouse十大最佳實踐技巧
本文字數(shù)16642估計閱讀時間42 分鐘作者Yonatan DolanClickHouse 是一款開源的列式數(shù)據(jù)庫管理系統(tǒng)專為對海量數(shù)據(jù)集進行實時分析查詢而設(shè)計。它擅長在數(shù)毫秒內(nèi)聚合數(shù)十億行數(shù)據(jù)使其成為分析平臺、可觀測性系統(tǒng)、實時儀表盤和數(shù)據(jù)倉庫的流行選擇。ClickHouse 通過其列式存儲格式、高效壓縮和向量化查詢執(zhí)行來實現(xiàn)這一目標但要獲得最佳性能需要理解如何與其架構(gòu)協(xié)同工作。盡管 ClickHouse 具備卓越的開箱即用性能但設(shè)計不佳的 Schema、低效的查詢或次優(yōu)的配置都可能浪費大量的性能潛力。一個原本能在數(shù)毫秒內(nèi)返回結(jié)果的表可能需要數(shù)秒。能實現(xiàn) 50 倍壓縮的存儲可能最終只能達到 10 倍。這種性能差距往往源于未能理解 ClickHouse 如何存儲、壓縮和查詢數(shù)據(jù)并應(yīng)用正確的技術(shù)來使您的用例與其優(yōu)勢相匹配。無論您是每天插入數(shù)十億事件、運行復(fù)雜的分析查詢還是努力降低存儲成本正確的優(yōu)化都能顯著提升性能和效率。對數(shù)據(jù)類型、表引擎或排序鍵的微小調(diào)整都可能帶來數(shù)量級的改進。在本文中我將分享 10 項最佳實踐這些是我作為 ClickHouse 解決方案架構(gòu)師在日常與客戶緊密合作中發(fā)現(xiàn)能夠帶來最大影響的。它們并非紙上談兵的理論建議而是我在各種規(guī)模的部署中反復(fù)運用并取得成效的模式涵蓋了從 Schema 設(shè)計、數(shù)據(jù)建模到查詢優(yōu)化和監(jiān)控等多個主題。將 ClickHouse 與 AI 代理一同使用如果您正通過 AI 代理或大型語言模型 (LLM) 應(yīng)用程序查詢 ClickHouse請查閱 ClickHouse best practices for AI agents獲取針對該用例的專屬指南(https://clickhouse.com/blog/introducing-clickhouse-agent-skills)。1. 選擇合適的主鍵和排序鍵在 ClickHouse 中表定義中的ORDER BY子句是您做出的最關(guān)鍵決策之一。它決定了數(shù)據(jù)在存儲中的物理排序方式這直接影響查詢通過主索引剪枝 (primary index pruning) 跳過無關(guān)數(shù)據(jù)的效率。同時它還會影響壓縮效率因為排序后的數(shù)據(jù)中相鄰行通常共享相似值從而能實現(xiàn)更高的壓縮比。ClickHouse 寫入數(shù)據(jù)時會根據(jù)您指定的ORDER BY列對行進行排序并在內(nèi)存中存儲每個數(shù)據(jù)顆粒granule默認為 8,192 行的首個值。在查詢時對這些列應(yīng)用的過濾器可讓 ClickHouse 跳過那些無法包含匹配數(shù)據(jù)的整個數(shù)據(jù)顆粒。關(guān)鍵在于使您的ORDER BY順序與最常見的查詢模式保持一致。優(yōu)先放置像tenant_id、region或category這樣的低基數(shù)low-cardinality列隨后是基于時間的列。應(yīng)避免以 UUIDs 或 timestamp 等高基數(shù)high-cardinality字段開頭因為它們幾乎無法提供裁剪優(yōu)化效果。讓我們以包含逾 1.5 億行數(shù)據(jù)的 Amazon reviews dataset 為例。假設(shè)一個表默認按(marketplace, customer_id, review_date)排序執(zhí)行以下查詢SELECT product_category, toStartOfMonth(review_date) AS month, count() AS review_count, avg(star_rating) AS avg_rating FROM amazon_reviews WHERE product_category Electronics AND toYear(review_date) 1999 GROUP BY product_category, month ORDER BY month;它會執(zhí)行一次全表掃描遍歷全部 1.5 億行數(shù)據(jù)以查找極小部分數(shù)據(jù)。如果我們更改表的ORDER BY順序為(product_category, review_date)我們的查詢將基于這些列進行過濾從而使相同的查詢運行速度提升 3 倍同時所需掃描的數(shù)據(jù)量減少 347 倍。對于相同的查詢和數(shù)據(jù)集如果ORDER BY順序與查詢模式匹配便能帶來顯著的不同。2. 使用高效數(shù)據(jù)類型ClickHouse 中的數(shù)據(jù)類型不僅僅關(guān)乎正確性它們直接影響存儲大小、壓縮比和查詢速度。選擇適合數(shù)據(jù)的最小類型除非NULL值確實具有實際意義否則避免使用Nullable(可為空) 類型對于低基數(shù)文本列使用LowCardinality(String)(低基數(shù)字符串) 類型以及對于固定值集合優(yōu)先選擇Enum(枚舉) 類型而非自由文本字符串可以顯著提升性能和存儲效率。同樣的邏輯也適用于整數(shù)類型當數(shù)據(jù)范圍允許時使用UInt8或UInt32代替UInt64意味著每次查詢需要讀取、解壓縮和處理的數(shù)據(jù)量更少。 被標記為Nullable(可為空) 的列要求 ClickHouse 額外存儲一個UInt8列來追蹤NULL值這會增加存儲和查詢執(zhí)行的雙重開銷。因此除非NULL值確實具有實際意義否則最好避免使用Nullable類型。在大多數(shù)情況下一個合理的默認值可以作為有效的替代方案文本字段使用空字符串、數(shù)值計數(shù)使用0、或者對于0是有效條目的 ID 字段使用像-1這樣的哨兵值。對于值集有限的字符串列LowCardinality(String)(低基數(shù)字符串) 類型在底層使用字典編碼這使得它在列中不同值少于約 10,000 個時效率更高。讓我們繼續(xù)以擁有 1.5 億行數(shù)據(jù)的 Amazon 評論數(shù)據(jù)集為例。一個設(shè)計不佳的表其中許多列是Nullable(可為空) 類型、數(shù)值字段過大、低基數(shù)文本列使用普通String類型會占用30.16 GB存儲空間。通過優(yōu)化即通過刪除Nullable(可為空) 類型、調(diào)整數(shù)值列大小、并在適當位置應(yīng)用LowCardinality(String)(低基數(shù)字符串) 類型將其切換到更合適的數(shù)據(jù)類型后存儲空間可降至26.8 GB。但其價值不僅僅體現(xiàn)在存儲方面它對性能也有顯著提升如下例所示查詢速度提高了2 倍。3. 考慮分區(qū)策略或避免使用分區(qū)ClickHouse 中的分區(qū) (partitioning) 是最容易被誤解的特性之一最常見的錯誤是將其用作性能優(yōu)化手段。ClickHouse 中的分區(qū)主要是一種數(shù)據(jù)管理特性而非通用的性能加速器。ClickHouse 通過主索引剪枝 (primary index pruning) 在數(shù)據(jù)跳過方面已經(jīng)極其快速。在此基礎(chǔ)上再進行分區(qū)很少有幫助反而常常適得其反。原因是 ClickHouse 需要大的數(shù)據(jù)塊 (parts)通常高達 150GB常含數(shù)十億行數(shù)據(jù)才能高效地進行壓縮和查詢并且數(shù)據(jù)塊 (parts) 永遠不會跨分區(qū)邊界合并。過度分區(qū)例如按天或按高基數(shù) (high-cardinality) 列如 tenant_id進行常常導(dǎo)致大量小數(shù)據(jù)塊 (parts)、合并速度變慢、內(nèi)存占用增加以及查詢性能下降。一個好的經(jīng)驗法則如果您創(chuàng)建了超過幾十個分區(qū)您很可能正在過度分區(qū)。那么何時應(yīng)該進行分區(qū)呢在兩種情況下對數(shù)據(jù)進行分區(qū)是很有價值的。第一種情況是基于 Time-to-Live (TTL) 的數(shù)據(jù)過期按月或按年分區(qū)可以高效地刪除整個舊數(shù)據(jù)分區(qū)而無需觸發(fā)變異 (mutation) 或合并 (merge) 操作這對于大型數(shù)據(jù)集來說比行級 TTL 效率高得多。第二種情況是與 ReplacingMergeTree、CollapsingMergeTree 或 AggregatingMergeTree 等合并型表引擎 (merge-oriented table engines) 配合使用時通過為歷史分區(qū)保留一個數(shù)據(jù)塊 (part)我們可以在帶有 FINAL 修飾符的查詢中獲得顯著的性能提升。除了這兩種情況在添加 PARTITION BY (分區(qū)子句) 之前請務(wù)必謹慎考慮。默認的不分區(qū)或者簡單的按月或按年分區(qū)通常是正確的選擇。為了說明不必要分區(qū)的成本我們在兩個結(jié)構(gòu)相同的表上使用了包含 1.5 億行 Amazon 評論的同一份數(shù)據(jù)集進行測試。其中一個表按review_date的月份進行分區(qū)另一個則未分區(qū)。數(shù)據(jù)攝入時間大致相同294 秒 對 314 秒但分區(qū)表在加載過程中消耗了多達 55% 的內(nèi)存4.71 GB 對 3.03 GB。真正的性能損耗體現(xiàn)在查詢階段。一個針對所有product_category值進行簡單聚合的查詢在未分區(qū)表上僅需 0.4 秒而在分區(qū)表上則耗時 20 秒。盡管掃描了完全相同的行數(shù)但性能下降了 46 倍。一個按helpful_votes進行 Top-100 排序的查詢也展現(xiàn)了類似但程度稍輕的性能差異未分區(qū)表耗時 40 秒分區(qū)表則耗時 92 秒。同樣的數(shù)據(jù)同樣的查詢速度卻慢了一倍以上。由于這兩個查詢均未對review_date進行過濾分區(qū)并未帶來任何剪枝 (pruning) 優(yōu)化。相反數(shù)據(jù)碎片化反而增加了每次掃描時的合并與調(diào)度開銷。4. 使用跳過索引 (Skipping Indexes) 優(yōu)化數(shù)據(jù)掃描ClickHouse 的主索引是基于ORDER BY字段構(gòu)建的稀疏索引是實現(xiàn)快速數(shù)據(jù)訪問最強大的工具。但在實際應(yīng)用中查詢并非總能通過主鍵列進行過濾。在這種情況下跳過索引 (Skipping Indexes) 能夠?qū)⑾嗤臄?shù)據(jù)粒度剪枝 (granule-pruning) 能力擴展到數(shù)據(jù)模型中的任意其他列。跳過索引是與數(shù)據(jù)一同存儲的輔助索引它不會改變數(shù)據(jù)的物理存儲和排序方式。跳過索引有多種類型我們可以將它們大致分為兩類輕量級索引 (Lightweight Indexes) 和重量級索引 (Heavyweight Indexes)。輕量級索引對寫入性能和存儲的影響微乎其微因此可以在任何有助于提升查詢效率的地方自由添加。而重量級索引則會帶來更高的存儲開銷和寫入放大 (write amplification) 成本。因此只有當查詢加速效果顯著且足以抵消這些額外開銷時才值得考慮使用。輕量級索引 (Lightweight Indexes)? minmax - 針對每個數(shù)據(jù)粒度 (granule) 存儲其最小值和最大值。最適用于數(shù)值或日期列對字符串列也可能有所幫助。其構(gòu)建與維護成本極低存儲開銷幾乎可以忽略不計。? set - 針對每個數(shù)據(jù)粒度存儲一小組獨特的distinct值。最適合經(jīng)常用于過濾條件但未包含在 ORDER BY 子句中的低基數(shù) (low-cardinality) 列??梢酝ㄟ^ set(0) 來存儲所有唯一值或者使用 set(N) 來設(shè)定上限當超出此上限時查詢將回退到全表掃描。重量級索引 (Heavyweight Indexes)bloom_filter- 一種概率型數(shù)據(jù)結(jié)構(gòu)用于判斷“某個值是否確定不在當前數(shù)據(jù)塊中”。最適用于高基數(shù)字符串列例如 ID 或 URL。它允許存在誤報但絕無漏報。由于會帶來顯著的存儲和寫入開銷因此僅當其帶來的掃描優(yōu)化能夠抵消其成本時才應(yīng)使用。ngrambf_v1/tokenbf_v1- 是bloom_filter的變體專門針對自由文本列上的LIKE或hasToken查詢進行了優(yōu)化。雖然在子字符串和詞元token搜索方面表現(xiàn)強大但其構(gòu)建和存儲成本較高因此僅應(yīng)在經(jīng)常進行搜索的列上使用。Text- 一種全新的自 26.2 版本起正式發(fā)布即 GA文本搜索專用倒排索引其功能類似于 Lucene/Elasticsearch 等系統(tǒng)中的倒排索引。它支持高精度的精確詞條term、前綴和子字符串匹配。它是文本搜索場景中最強大的選擇但同時在存儲和寫入放大方面也是開銷最大的。當Bloom_filter無法滿足您的性能需求時可選用Text索引。通過 Amazon 評論數(shù)據(jù)集可以很好地說明跳過索引skipping index的優(yōu)勢。當執(zhí)行一個total_votes 1000的過濾查詢時如果沒有跳過索引系統(tǒng)將對全部 1.5 億行數(shù)據(jù)執(zhí)行全表掃描。若在total_votes列上添加一個minmax索引這是開銷最低的索引之一掃描的行數(shù)將降至 2900 萬行實現(xiàn)高達80% 的數(shù)據(jù)掃描量減少且?guī)缀醪粠眍~外開銷。5. Leveraging the JSON Data Type for semi-structured dataClickHouse 的原生JSON數(shù)據(jù)類型是處理半結(jié)構(gòu)化數(shù)據(jù)的強大工具特別適用于那些鍵值不可預(yù)測、隨時間變化或包含多種類型值的場景。它能夠在插入數(shù)據(jù)時自動推斷類型并將每個被發(fā)現(xiàn)的路徑存儲為獨立的子列受限于max_dynamic_paths的定義從而為動態(tài)數(shù)據(jù)提供列式存儲的性能優(yōu)勢。然而這種靈活性并非沒有代價。JSON類型在每次數(shù)據(jù)插入時都會執(zhí)行類型推斷這相比靜態(tài) Schema 會帶來額外的開銷。此外當同一路徑下包含多種類型的值時它還會占用更多的存儲空間。對于結(jié)構(gòu)已知且一致的數(shù)據(jù)即使數(shù)據(jù)以 JSON 格式傳輸采用帶有顯式列類型的靜態(tài) Schema 也將始終比JSON類型表現(xiàn)出更優(yōu)的性能。在使用 JSON (JavaScript Object Notation) 數(shù)據(jù)時一個關(guān)鍵參數(shù)是max_dynamic_paths它控制 ClickHouse 將多少個不同的 JSON 路徑作為單獨的子列進行存儲。默認情況下一旦超出此限制其他路徑將被存儲在一個共享結(jié)構(gòu)中這會降低查詢效率。默認值為 1024但對于路徑集有限且結(jié)構(gòu)明確的有效載荷將其設(shè)置得更低可以使數(shù)據(jù)結(jié)構(gòu)更緊湊、更可預(yù)測。當您知道某些路徑始終存在且類型固定時可以使用 JSON 提示 (hints) 明確聲明這些路徑。例如CREATE TABLE events ( id UInt64, payload JSON(timestamp DateTime, level LowCardinality(String)) ) ENGINE MergeTree ORDER BY id;提示 (Hints) 為 ClickHouse 提供了有關(guān)這些路徑的更多信息這些路徑像常規(guī)列一樣被存儲和壓縮而有效載荷的其余部分則保持完全動態(tài)。在將 Amazon Reviews 數(shù)據(jù)集轉(zhuǎn)換為文檔型數(shù)據(jù)集時相比不使用提示的 JSON使用提示可將存儲空間減少 38%同時此示例查詢的速度在使用提示時比不使用提示時提高了 26%。SELECT count(*), review_data.product_category PC FROM amazon_reviews_json GROUP BY pc然而這不僅是為了優(yōu)化存儲和提升性能提示路徑也是跳過索引 (skipping indexes) 的可靠目標而完全動態(tài)的路徑在不同數(shù)據(jù)粒度 (granules) 之間可能存在不一致從而導(dǎo)致索引效率較低。需要指出的是雖然可以在任何 JSON 路徑上添加跳過索引但這需要進行類型轉(zhuǎn)換 (casting)。總而言之如果數(shù)據(jù)結(jié)構(gòu)扁平且可預(yù)測應(yīng)使用顯式列 (explicit columns)。如果數(shù)據(jù)存在可預(yù)測的核心結(jié)構(gòu)但伴隨動態(tài)變化則考慮對已知部分使用靜態(tài)列 (static columns)其余部分使用單個JSON列。只有當數(shù)據(jù)模式完全不可預(yù)測時才應(yīng)考慮使用完全動態(tài)的JSON列。6. 正確地將數(shù)據(jù)導(dǎo)入 ClickHouse如何高效地將數(shù)據(jù)插入 ClickHouse 是一個值得深入探討的重要議題。數(shù)據(jù)攝取 (ingestion) 模式通常有四種每種模式都有其推薦的方法和最佳實踐。對象存儲(Object Storage)如 Amazon S3、GCS、Azure Blob是批量加載最常見的數(shù)據(jù)源之一。在有格式選擇時建議優(yōu)先選擇 Parquet 或 ORC 等列式格式而不是 JSON 或 Avro 等行式格式ClickHouse 可以僅從 Parquet 和 ORC 格式中讀取所需列完全跳過其余部分而 JSON 則需要解析每一行的每個字段。即使在加載所有列時列式格式也更快因為數(shù)據(jù)到達時已按照 ClickHouse 內(nèi)部存儲的方式組織從而減少了攝取過程中的轉(zhuǎn)換開銷。加載 Amazon reviews 數(shù)據(jù)集清楚地說明了這一點Parquet 和 ORC 格式加載耗時79 秒Avro 格式耗時94 秒JSON 格式耗時105 秒。對于從對象存儲進行托管式持續(xù)數(shù)據(jù)攝取ClickPipes 直接支持 S3 和 GCS 數(shù)據(jù)源。數(shù)據(jù)庫的CDC(Change Data Capture)如 Postgres、MySQL、MongoDB 等和事件流如 Kafka、Kinesis 等最好通過 ClickHouse Cloud 的原生托管式攝取服務(wù) ClickPipes 來處理。ClickPipes 開箱即用地支持模式映射、偏移量管理、錯誤處理和背壓。針對 CDC它采用基于日志的方法以最小的源數(shù)據(jù)庫負載捕獲每一行級別的變更。如果您的數(shù)據(jù)庫位于私有 VPC (Virtual Private Cloud) 中ClickPipes 支持反向 PrivateLink從而實現(xiàn)安全連接而無需將數(shù)據(jù)庫暴露給公共互聯(lián)網(wǎng)。后端應(yīng)用程序直接寫入 ClickHouse 是企業(yè)非常普遍的做法但這確實需要考慮一些事項。ClickHouse 針對大型、不頻繁的批次進行了優(yōu)化而非應(yīng)用程序代碼中常見的小型、頻繁的插入。每次插入都會在存儲層中創(chuàng)建至少一個部分 (part)而過多的小部分會導(dǎo)致合并壓力 (merge pressure)、內(nèi)存使用量升高并最終導(dǎo)致插入限流 (insert throttling)。兩種解決方案是客戶端批量處理累積行并在每隔幾秒或幾千行時刷新或者啟用異步插入(async inserts)這讓 ClickHouse 自動緩沖傳入的插入并以批次形式刷新它們SET async_insert 1; SET wait_for_async_insert 1;當wait_for_async_insert 1時客戶端會等待數(shù)據(jù)寫入分片part的確認這為您提供了小批量寫入的便利并具備適當?shù)拇_認機制和可靠的錯誤處理能力。您可以通過system.asynchronous_insert_log監(jiān)控異步插入行為從而針對您的工作負載調(diào)整刷新間隔和緩沖區(qū)大小。無論采用何種數(shù)據(jù)導(dǎo)入方式請避免一次只插入一行數(shù)據(jù)在可能的情況下優(yōu)先選擇原生二進制格式而非 JSON并通過監(jiān)控system.parts中的分片part數(shù)量盡早發(fā)現(xiàn)數(shù)據(jù)導(dǎo)入問題。7. 寫入時計算借助物化視圖Materialized View和投影Projection實現(xiàn)更快的讀取物化視圖和投影都遵循相同的核心思想在數(shù)據(jù)插入時執(zhí)行計算從而使讀取操作更快并減少計算資源消耗。與在查詢時進行掃描和聚合不同您可以選擇在數(shù)據(jù)到達時預(yù)先計算并存儲結(jié)果。兩者的權(quán)衡取舍是一致的更快的讀取是以增加存儲空間和額外的寫入開銷為代價的。投影是存儲在同一表內(nèi)部的替代排序方式或預(yù)聚合數(shù)據(jù)。當 ClickHouse 執(zhí)行查詢時如果查詢的過濾和排序模式與某個投影匹配它會自動選擇最佳投影因此無需對查詢進行任何修改。這使得它們對應(yīng)用程序透明易于采用。缺點在于每次插入操作都必須為每個投影寫入和排序數(shù)據(jù)這會增加插入延遲和存儲占用。在圍繞投影制定查詢優(yōu)化策略之前有必要驗證它們是否真正在查詢時被選中。最簡單的方法是啟用以下設(shè)置SET force_optimize_projection 1;啟用此設(shè)置后如果您的查詢沒有找到合適的投影ClickHouse 將拋出錯誤從而立即明確您的投影是正在被使用抑或是被默默忽略。關(guān)于投影需要強調(diào)的一點是它們常常被“以防萬一”地添加這會影響存儲和寫入成本。首先應(yīng)該使用設(shè)計良好的主鍵并識別出實際運行緩慢的查詢?nèi)缓笾辉谡嬲枰牡胤教砑油队?。讓實際使用數(shù)據(jù)來指導(dǎo)投影的定義。物化視圖 (Materialized views)有兩種類型。可刷新物化視圖 (Refreshable materialized views)的工作方式與傳統(tǒng)數(shù)據(jù)倉庫中的預(yù)期一致它們會按計劃重新計算結(jié)果因此適用于復(fù)雜的轉(zhuǎn)換。但這種方式通常需要管理已處理數(shù)據(jù)的“書簽”以區(qū)分已處理和未處理的數(shù)據(jù)在遇到延遲數(shù)據(jù)或歷史數(shù)據(jù)回填時需要進行重新處理同時強烈建議在處理過程中考慮冪等性。增量物化視圖 (Incremental materialized views)是 ClickHouse 的獨特之處它們更靈活但也需要更精心設(shè)計。它們充當插入觸發(fā)器對每個傳入批次運行SELECT查詢并將結(jié)果寫入目標表。這使得它們在數(shù)據(jù)到達時能夠極其高效地持續(xù)維護聚合、匯總或扇出數(shù)據(jù)管道。一個重要的限制是它們僅在插入操作時觸發(fā)對源表的刪除和更新操作不會傳播因此它們最適合僅追加或不可變的數(shù)據(jù)模式。增量物化視圖中的連接操作值得特別關(guān)注因為只有連接中的左表會觸發(fā)視圖更新。如果右側(cè)表發(fā)生變化物化視圖將不會更新。此外物化視圖的良好可組合性也值得了解單個源表可以“扇出”到多個物化視圖MV每個 MV 維護不同的聚合或轉(zhuǎn)換同時來自不同源表的多個 MV 也可以匯聚到同一個目標表。這使得它們成為構(gòu)建更復(fù)雜數(shù)據(jù)管道的強大基石。在 ClickHouse 中一種常見模式是利用物化視圖來維護用于儀表盤和高頻查詢的預(yù)聚合匯總表同時保留原始表以進行即席探索。8. 了解你的系統(tǒng)表ClickHouse 的系統(tǒng)表是其最強大的內(nèi)置功能之一。集群中發(fā)生的一切包括查詢、合并、后臺活動和錯誤都被捕獲并可以通過標準 SQL 進行查詢從而使用標準 SQL 為你提供深入的可觀測性。在多副本服務(wù)中查詢系統(tǒng)表僅會顯示當前查詢所在副本的日志。若要獲取所有副本的完整視圖需使用clusterAllReplicas。此外由于許多系統(tǒng)表會輪轉(zhuǎn)歷史數(shù)據(jù)可能不會直接顯示除非你顯式地通過merge表函數(shù)對它們進行合并。以下是如何查詢system.query_log以確保獲取表中所有服務(wù)日志的示例SELECT event_time, query_id, query, type FROM clusterAllReplicas(default, merge(system, ^query_log*)) WHERE event_time Now() - toIntervalMinute(5);system.query_log和system.parts是兩個最值得熟悉的系統(tǒng)表。system.query_log是理解查詢行為的主要工具。每個查詢會根據(jù)事件QueryStart、QueryFinish、ExceptionBeforeStart或ExceptionWhileProcessing生成一行記錄從而提供服務(wù)上所有查詢的完整生命周期視圖。每行數(shù)據(jù)會捕獲查詢耗時 (query_duration_ms)、資源使用情況 (read_rows、read_bytes、memory_usage)、查詢文本本身以及所涉及的數(shù)據(jù)庫、表、列和投影。在錯誤排查時還可以利用exception_code、exception和stack_trace。ProfileEvents列則提供了更深入的洞察它是一個低級執(zhí)行計數(shù)器的映射能夠精確揭示時間開銷分布從 CPU 周期到 I/O 讀取再到緩存命中。當查詢速度低于預(yù)期時ProfileEvents常常能幫助我們判斷瓶頸是在 I/O、CPU 還是網(wǎng)絡(luò)。system.parts表詳細展示了您的存儲中所有 MergeTree 系列表MergeTree-family tables的每個物理數(shù)據(jù)部分的信息。每行對應(yīng)一個數(shù)據(jù)部分使其成為監(jiān)控存儲、診斷合并行為和理解表健康狀況的理想選擇。其中最關(guān)鍵的列包括active指示一個數(shù)據(jù)部分是當前活躍的還是已完成合并后留下的舊部分因此通過active 1進行過濾可確保查詢只關(guān)注活躍的相關(guān)部分。partition和partition_id顯示了每個數(shù)據(jù)部分所屬的分區(qū)而rows、bytes_on_disk、data_compressed_bytes和data_uncompressed_bytes則清晰地展示了數(shù)據(jù)部分的大小和壓縮效率。part_type區(qū)分Wide和Compact兩種數(shù)據(jù)部分它們決定了列的存儲方式。在Wide格式中每個列都存儲在各自獨立的文件中這是較大數(shù)據(jù)部分的標準格式并在讀取時實現(xiàn)了高效的列裁剪column pruning。Compact格式將所有列存儲在單個文件中默認小于 10MB這減少了文件句柄file handle的數(shù)量對于行數(shù)較少的小型數(shù)據(jù)部分而言效率更高。值得我們隨時取用的兩個查詢是各表的數(shù)據(jù)部分數(shù)量和大小SELECT table, count() AS parts, sum(rows) AS total_rows, formatReadableSize(sum(bytes_on_disk)) AS size_on_disk FROM system.parts WHERE active GROUP BY table ORDER BY parts DESC;過度分區(qū)表SELECT table, partition, count() AS parts FROM system.parts WHERE active GROUP BY table, partition HAVING parts 10 ORDER BY parts DESC;9. 精通 ReplacingMergeTreeReplacingMergeTree是 ClickHouse 中備受歡迎的表引擎之一它用于支持需要去重deduplication或更新插入upserts的場景。此表引擎根據(jù)指定列例如版本/時間戳保留每行的最新版本。去重操作依據(jù)ORDER BY列的唯一性進行。舊的重復(fù)數(shù)據(jù)會在后臺合并background merges過程中被舍棄。需要注意的是這些合并是異步進行的這意味著在查詢時表中可能仍然存在重復(fù)行。若要獲取正確的結(jié)果需要使用FINAL或argMax模式并深入理解它們之間的權(quán)衡。FINAL是最簡單的方式只需將其添加到查詢中ClickHouse 就會透明地處理去重操作。然而代價是FINAL在返回結(jié)果之前必須協(xié)調(diào)reconcile所有的數(shù)據(jù)部分其性能與查詢時存在的數(shù)據(jù)部分數(shù)量直接相關(guān)。在一個合并良好、分區(qū)中只有一個數(shù)據(jù)部分的表上使用FINAL與否性能差異不大。而在一個處于數(shù)據(jù)攝取ingestion中期、存在大量數(shù)據(jù)部分的表上它可能帶來顯著的性能開銷。SELECT star_rating FROM mytests.amazon_reviews_rmt FINAL WHERE review_id review_idargMax模式是一種替代方案它將去重邏輯整合到聚合操作本身中從具有最高版本的行中選取值SELECT argMax(star_rating, review_date) FROM mytests.amazon_reviews_rmt WHERE review_id review_id在包含 1.52 億行1.5 億原始行 200 萬重復(fù)行的 Amazon reviews 數(shù)據(jù)集上這兩種方法的性能差異與表的狀態(tài)密切相關(guān)。在存在 9 個未合并的數(shù)據(jù)分塊時上述使用FINAL的查詢耗時 1.5 秒而argMax耗時 1.0 秒。為了展示數(shù)據(jù)分塊更少時的差異我們強制將這些數(shù)據(jù)分塊合并為一個單一分塊此時兩種方法的性能均下降到大致相同的水平0.48 秒對比 0.40 秒。盡管具體結(jié)果可能因查詢形態(tài)、基數(shù)和數(shù)據(jù)分塊數(shù)量而異但這一規(guī)律依然成立無論合并狀態(tài)如何argMax都表現(xiàn)出更高的穩(wěn)定性而FINAL則隨著數(shù)據(jù)分塊的合并性能顯著提升。實際上對于日常查詢或當表數(shù)據(jù)合并良好時FINAL是一個更簡單的選擇。而當處理有活躍寫入的表并且需要可預(yù)測的延遲時argMax則更值得選用。在生產(chǎn)環(huán)境中減少FINAL性能不穩(wěn)定性的一種方法是配置后臺合并使其對舊數(shù)據(jù)處理得更積極。默認情況下ClickHouse 會根據(jù)內(nèi)部啟發(fā)式算法合并數(shù)據(jù)分塊該算法會考慮數(shù)據(jù)分塊的大小、數(shù)量和創(chuàng)建時間但并沒有強制將一個分區(qū)的數(shù)據(jù)合并成一個單一分塊的機制。這意味著一個表可以無限期地保持每個分區(qū)擁有多個數(shù)據(jù)分塊從而導(dǎo)致FINAL持續(xù)產(chǎn)生額外開銷。min_age_to_force_merge_seconds設(shè)置改變了這一默認行為它會強制 ClickHouse 不斷合并早于指定閾值的數(shù)據(jù)分塊直到每個分區(qū)只剩下一個數(shù)據(jù)分塊min_age_to_force_merge_seconds 600, min_age_to_force_merge_on_partition_only 1;請注意這樣做可能會增加后臺合并的負載因為 ClickHouse 會持續(xù)合并數(shù)據(jù)分塊直到每個分區(qū)只剩下一個從而占用更多本可用于查詢或?qū)懭氲?CPU 和 I/O 資源。min_age_to_force_merge_on_partition_only 1標志確保此操作僅在所有數(shù)據(jù)塊parts都已足夠舊的分區(qū)上觸發(fā)從而避免干擾仍在活躍寫入的分區(qū)。值得注意的是為了使此設(shè)置在實踐中有效表應(yīng)該進行分區(qū)。如果沒有分區(qū)所有數(shù)據(jù)將存儲在單個分區(qū)中可能積累過多的數(shù)據(jù)。由于 ClickHouse 默認不會合并會使數(shù)據(jù)塊大小超過 150GB 的分塊因此將所有數(shù)據(jù)整合為單個數(shù)據(jù)塊變得不切實際。通過按月或按年分區(qū)每個分區(qū)都將保持在可控的尺寸范圍內(nèi)從而能夠合并為單個數(shù)據(jù)塊這正是FINAL操作性能最佳的狀態(tài)。10. 優(yōu)化你的 JOIN過去ClickHouse 中的 JOIN 曾是建議用戶謹慎使用的一個特性普遍的建議是盡可能通過反范式化denormalization、字典dictionaries或物化視圖materialized views來避免使用 JOIN。這一建議在當時是合理的但顯著的引擎級改進使 JOIN 在高并發(fā)生產(chǎn)工作負載中變得越來越可行。作為默認查詢執(zhí)行層引入的 Analyzer查詢優(yōu)化器為 JOIN 規(guī)劃帶來了重大改進ClickHouse 24.4 引入了更好的謂詞下推predicate pushdown功能通過將過濾條件推送到 JOIN 的兩側(cè)可將查詢性能提升 10 倍版本 24.12 獲得了自動重新排序雙表 JOIN 的能力將較小的表放在右側(cè)25.9 則將此功能擴展到連接三個或更多表的查詢。結(jié)合多種 JOIN 算法可供選擇以平衡不同的內(nèi)存和性能考量如今 ClickHouse 中的 JOIN 其能力顯著增強也更容易正確使用甚至比一年前有了巨大的提升。盡管如此JOIN 在分析型數(shù)據(jù)庫中仍然伴隨著開銷因此有幾項原則值得遵循。對于對毫秒級延遲有嚴格要求的實時工作負載目標是每個查詢最多包含 3 到 4 個 JOIN。此外反范式化、字典或預(yù)聚合物化視圖是值得考慮用于進一步提升查詢性能的工具。對于靜態(tài)或變化緩慢的查找推薦使用字典。當需要用不常變動的小型參考表數(shù)據(jù)來豐富大型表時字典的性能將優(yōu)于常規(guī)連接。字典會完全加載到內(nèi)存中并通過dictGet進行訪問從而徹底繞過哈希連接過程。以客戶元數(shù)據(jù)豐富后的 Amazon reviews 數(shù)據(jù)集為例性能差異顯著在 1.5 億行數(shù)據(jù)上執(zhí)行常規(guī)JOIN操作耗時2.3 秒與字典表進行連接耗時1.36 秒而dictGet操作僅需0.86 秒這比基準連接快了近 3 倍且底層數(shù)據(jù)無需修改??偨Y(jié)ClickHouse 開箱即用即表現(xiàn)出極快的速度但要充分發(fā)揮其潛力就必須深入理解其數(shù)據(jù)存儲、合并和查詢機制。本文介紹的最佳實踐并非孤立存在而是相輔相成。精心選擇的ORDER BY子句通常能使跳躍索引 (skipping indexes) 更為高效。恰當?shù)臄?shù)據(jù)類型能夠減輕物化視圖和投影的工作負擔。明智的分區(qū)策略能讓 ReplacingMergeTree (ReplacingMergeTree) 和基于 TTL 的過期策略 (TTL-based expiration) 有序運行。優(yōu)化數(shù)據(jù)攝取過程能保持健康的數(shù)據(jù)分片數(shù)量進而確保FINAL操作的執(zhí)行效率。本文中貫穿使用的 Amazon reviews 數(shù)據(jù)集基準測試表明這些并非微不足道的提升選擇正確的主鍵能將掃描數(shù)據(jù)量減少 347 倍正確的數(shù)據(jù)類型能將存儲空間削減 12% 并將查詢時間縮短 50%不必要的分區(qū)可能導(dǎo)致查詢速度降低 46 倍而字典查找的性能可比常規(guī)連接快 3 倍。這些都是純粹源于設(shè)計決策而非硬件升級所帶來的數(shù)量級差異。如果你是 ClickHouse 的初學(xué)者應(yīng)重點關(guān)注前兩點主鍵設(shè)計和數(shù)據(jù)類型。它們的影響最為廣泛適用于你創(chuàng)建的每個表。在此基礎(chǔ)上在查詢需要時添加跳躍索引僅在有明確理由時進行分區(qū)并根據(jù)具體用例需求采用物化視圖和 ReplacingMergeTree。ClickHouse 會回饋那些深入理解其架構(gòu)的用戶。你的 schema 和查詢與 ClickHouse 數(shù)據(jù)管理方式越是契合你的系統(tǒng)就將越快、越高效。在理想情況下這意味著你能夠攝取數(shù)十億行數(shù)據(jù)并以毫秒級的速度查詢它們。關(guān)于我們ClickHouse 是面向 AI 時代打造的高性能實時分析數(shù)據(jù)庫能夠以極致性能處理海量數(shù)據(jù)分析任務(wù)。憑借高并發(fā)、低延遲和云原生架構(gòu)ClickHouse 廣泛應(yīng)用于可觀測性、數(shù)據(jù)倉庫、實時分析及 AI 數(shù)據(jù)基礎(chǔ)設(shè)施等場景。我們致力于幫助企業(yè)在公有云平臺上構(gòu)建安全、彈性且高性價比的實時分析與 AI 數(shù)據(jù)平臺加速釋放數(shù)據(jù)價值推動智能化創(chuàng)新與數(shù)字化轉(zhuǎn)型。目前Trip.com、DiDi、Meta、Sony、Netflix、Deutsche Bank、Sierra、Cloudflare 等全球領(lǐng)先企業(yè)均在使用 ClickHouse 支撐其關(guān)鍵業(yè)務(wù)和數(shù)據(jù)分析平臺。

相關(guān)新聞

【單片機畢業(yè)設(shè)計】基于嵌入式的井下氣體液位井蓋狀態(tài)監(jiān)測平臺 基于單片機的市政窨井智能檢測報警設(shè)備設(shè)計(016201)

【單片機畢業(yè)設(shè)計】基于嵌入式的井下氣體液位井蓋狀態(tài)監(jiān)測平臺 基于單片機的市政窨井智能檢測報警設(shè)備設(shè)計(016201)

博主介紹:??碼農(nóng)一枚 ,專注于大學(xué)生項目實戰(zhàn)開發(fā)、講解和畢業(yè)🚢文撰寫修改等。全棧領(lǐng)域優(yōu)質(zhì)創(chuàng)作者,博客之星、掘金/華為云/阿里云/InfoQ等平臺優(yōu)質(zhì)作者、專注于嵌入式單片機,Java、小程序技術(shù)領(lǐng)域和畢業(yè)項目實戰(zhàn) ??…

2026/8/2 6:35:01 閱讀更多
運算放大器學(xué)習(xí)筆記-虛短和虛斷

運算放大器學(xué)習(xí)筆記-虛短和虛斷

虛斷:由于運放的差模輸入電阻很大,一般通用型運算放大器的輸入電阻都在1MΩ以上。因此流入運放輸入端的電流往往不足1uA,遠小于輸入端外電路的電流。故通??砂堰\放的兩輸入端視為開路,且輸入電阻越大,兩輸入端越接近開…

2026/8/2 6:35:01 閱讀更多
PaperBanana:多智能體協(xié)作如何實現(xiàn)學(xué)術(shù)圖表自動化生成與優(yōu)化

PaperBanana:多智能體協(xié)作如何實現(xiàn)學(xué)術(shù)圖表自動化生成與優(yōu)化

1. 項目概述:當學(xué)術(shù)配圖遇上AI智能體最近在學(xué)術(shù)圈和AI開發(fā)社區(qū)里,一個名為PaperBanana的項目引起了不小的討論。這個由北京大學(xué)和谷歌的研究人員聯(lián)合開源的工具,號稱能用5個智能體(Agent)搞定論文配圖的所有工作&#…

2026/8/2 6:25:00 閱讀更多
3分鐘搞定!QQ空間歷史說說完整備份終極指南

3分鐘搞定!QQ空間歷史說說完整備份終極指南

3分鐘搞定!QQ空間歷史說說完整備份終極指南 【免費下載鏈接】GetQzonehistory 獲取QQ空間發(fā)布的歷史說說 項目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否曾想過,那些年發(fā)過的QQ空間說說,那些記錄青春的文字…

2026/8/2 0:04:01 閱讀更多
3分鐘搞定!QQ空間歷史說說完整備份終極指南

3分鐘搞定!QQ空間歷史說說完整備份終極指南

3分鐘搞定!QQ空間歷史說說完整備份終極指南 【免費下載鏈接】GetQzonehistory 獲取QQ空間發(fā)布的歷史說說 項目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否曾想過,那些年發(fā)過的QQ空間說說,那些記錄青春的文字…

2026/8/2 0:04:01 閱讀更多
AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O分配PCB板是應(yīng)用材料(Applied Materials)公司生產(chǎn)的一款用于半導(dǎo)體設(shè)備的I/O信號分配電路板。該型號(0100-02186)的核心特點如下:專用于Endura等半導(dǎo)體工藝腔室。集成信號路由與分配功能。連接控制…

2026/8/2 2:51:21 閱讀更多
Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動機

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動機

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動機是日本日清(Nissei)品牌的一款工業(yè)用三相異步電機,適用于自動化設(shè)備及通用機械驅(qū)動。該型號(FFMN-32L-10-T0 40AX)的核心特點如下:三相交流異步電動機。額定…

2026/8/2 2:52:49 閱讀更多