優化器 (CBO) 對 LIKE 條件的基數估算直接影響執行計劃選擇。本文通過實測驗證不同 LIKE 模式的選擇率計算邏輯。
DROP TABLE test PURGE;
CREATE TABLE test AS SELECT * FROM dba_objects;
EXEC dbms_stats.gather_table_stats(USER, 'TEST');
SELECT COUNT(*) FROM test; -- 79,747 行
SELECT COUNT(*) FROM test WHERE object_name LIKE 'test%'; -- 0 行
SELECT COUNT(*) FROM test WHERE object_name LIKE '%test%'; -- 12 行
SELECT COUNT(*) FROM test WHERE object_name LIKE '%test'; -- 2 行
%test% / %test
SELECT * FROM test WHERE object_name LIKE '%test%';
-- Plan hash: 1357081020
-- Rows (估算): 3,987 = 79,747 × 5%
-- Operation: TABLE ACCESS FULL
SELECT * FROM test WHERE object_name LIKE '%test';
-- Rows (估算): 3,987 = 79,747 × 5%
test%
SELECT * FROM test WHERE object_name LIKE 'test%';
-- Rows (估算): 2 (根據直方圖/密度精確估算)
t%
SELECT * FROM test WHERE object_name LIKE 't%';
-- Rows (估算): 1,079 (根據首字母頻率估算)
| LIKE 模式 | 選擇率估算邏輯 | 備註 |
|---|---|---|
%pattern% (前導 %) | 固定 5% (硬編碼默認值) | 無法使用索引範圍掃描,通常全表掃描 |
%pattern (前導 %) | 固定 5% | 同前 |
pattern% (後置 %) | 根據列統計信息 (直方圖/密度/NDV) 計算 | 可使用索引範圍掃描,估算較準 |
_pattern% (單字符通配) | 根據首字符頻率估算 | 可用索引 |
_optimizer_like_selectivity = 0.05 (隱藏參數,可修改但不建議)。DBA_TAB_COL_STATISTICS 中的 DENSITY、NUM_DISTINCT、HISTOGRAM) 進行精確估算。DBMS_STATS.GATHER_TABLE_STATS 默認 METHOD_OPT => 'FOR ALL COLUMNS SIZE AUTO' 會自動收集高頻列直方圖,顯著提升 LIKE 估算準確度。EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'TAB', METHOD_OPT => 'FOR COLUMNS SIZE 254 COL_NAME')CREATE INDEX idx_upper_name ON test(UPPER(object_name)) 配合 WHERE UPPER(object_name) LIKE 'TEST%'。OPT_DYNAMIC_SAMPLING 或 Hint /*+ DYNAMIC_SAMPLING(4) */ 讓優化器運行時採樣修正估算。/*+ CARDINALITY(t 100) */ 強制指定估算行數 (臨時方案)。
SELECT table_name, column_name, num_distinct, density, histogram
FROM user_tab_col_statistics
WHERE table_name = 'TEST' AND column_name = 'OBJECT_NAME';