Prewhere 和 where 語句的作用相同,用來過濾數據。不同之處在於 prewhere 只支持 *MergeTree 族系列引擎的表,首先會讀取指定的列數據,來判斷數據過濾,等待數據過濾之後再讀取 select 聲明的列字段來補全其余屬性。
當查詢列明顯多於篩選列時使用 Prewhere 可十倍提升查詢性能,Prewhere 會自動優化執行過濾階段的數據讀取方式,降低 io 操作。
在某些場合下,prewhere 語句比 where 語句處理的數據量更少性能更高。
默認情況,我們肯定不會關閉 where 自動優化成 prewhere,但是某些場景即使開啟優化,也不會自動轉換成 prewhere,需要手動指定 prewhere:
通過采樣運算可極大提升數據分析的性能
采樣修飾符只有在 MergeTree engine 表中才有效,且在創建表時需要指定采樣策略。
數據量太大時應避免使用 select * 操作,查詢的性能會與查詢的字段大小和數量成線性表,換字段越少,消耗的 io 資源越少,性能就會越高。
分區裁剪就是只讀取需要的分區,在過濾條件中指定。
千萬以上數據集進行 order by 查詢時需要搭配 where 條件和 limit 語句壹起使用。
如非必須,不要在結果集上構建虛擬列,虛擬列非常消耗資源浪費性能,可以考慮在前端進行處理,或者在表中構造實際字段進行額外存儲。
性能可提升 10 倍以上,uniqCombined 底層采用類似 HyperLogLog 算法實現,能接受 2%左右的數據誤差,可直接使用這種去重方式提升查詢性能。Count(distinct) 會使用 uniqExact 精確去重。
不建議在千萬級不同數據上執行 distinct 去重查詢,改為近似去重 uniqCombine
為了避免因個別慢查詢引起的服務雪崩的問題,除了可以為單個查詢設置超時以外,還可以配置周期熔斷,在壹個查詢周期內,如果用戶頻繁進行慢查詢操作超出規定閾值後將無法繼續進行查詢操作。
物理內存和虛擬內存的數據交換,會導致查詢變慢,資源允許的情況下關閉虛擬內存。
為每壹個賬戶添加 join_use_nulls 配置,左表中的壹條記錄在右表中不存在,右表的相應字段會返回該字段相應數據類型的默認值,而不是標準 SQL 中的 Null 值。
批量寫入數據時,必須控制每個批次的數據中涉及到的分區的數量,在寫入之前最好對需要導入的數據進行排序。無序的數據或者涉及的分區太多,會導致 ClickHouse 無法及時對新導入的數據進行合並,從而影響查詢性能。
cpu 壹般在 50%左右會出現查詢波動,達到 70%會出現大範圍的查詢超時,cpu 是最關鍵的指標,要非常關註。
clickhouse的多表關聯會把有表的數據全部加入到內存中,然後左表每條去和內存中的數據做對比。壹旦左表數據量過大,容易導致內存不夠。
當多表聯查時,查詢的數據僅從其中壹張表出時,可以考慮用 IN 操作而不是 join。
多表 join 時要滿足 小表在右 的原則,右表關聯時被加載到內存中與左表進行比較,ClickHouse 中無論是 Left join 、Right join 還是 Inner join 永遠都是拿著右表中的每壹條記錄到左表中查找該記錄是否存在,所以右表必須是小表。
ClickHouse 在 join 查詢時不會主動發起謂詞下推的操作,需要每個子查詢提前完成過濾操作,需要註意的是,是否執行謂詞下推,對性能影響差別很大(新版本中已經不存在此問題,但是需要註意謂詞的位置的不同依然有性能的差異)
兩張分布式表上的 IN 和 JOIN 之前 必須加上 GLOBAL 關鍵字 ,右表只會在接收查詢請求的那個節點查詢壹次,並將其分發到其他節點上。如果不加 GLOBAL 關鍵字的話,左分布式表的每個節點都會單獨發起壹次對右表的查詢,而右表又是分布式表,就導致右表壹***會被查詢 N?次(N是該分布式表的分片數量),這就是查詢放大,會帶來很大開銷。
將壹些需要關聯分析的業務創建成字典表進行 join 操作,前提是字典表不宜太大,因為字典表會常駐內存, 官方地址
通過增加邏輯過濾可以減少數據掃描,達到提高執行速度及降低內存消耗的目的