本文為您介紹PolarDB-X的自動FORCE INDEX機制。
背景資訊
當一條查詢SQL(邏輯SQL)發往PolarDB-X時,PolarDB-X的計算節點的最佳化器會將其分成可下推和不可下推的兩部分,可下推的部分也被稱為物理SQL。大多數情況下,物理SQL會直接發送給儲存節點,由PolarDB-X的儲存節點基於代價選擇合適的局部索引。
由於代價模型缺陷、統計資訊不準確等問題,基於代價選擇索引的模式可能會出現索引選錯。因此在某些確定性情境下,計算節點會基於規則選擇合適的局部索引,使用FORCE INDEX指定索引將其添加到物理SQL中,幹預儲存節點的索引選擇,減少錯誤發生的機率。
支援版本
對於5.4.18-17181576之前的執行個體,無自動FORCE INDEX機制。
對於初次購買版本在5.4.18-17181576之前並升級到5.4.18-17181576及以上的執行個體,預設關閉自動FORCE INDEX機制。
對於新購執行個體
計算節點組件版本低於5.4.18,無自動FORCE INDEX機制。
計算節點組件版本為5.4.18,小版本低於17181576,無自動FORCE INDEX機制;小版本不低於17181576,預設開啟自動FORCE INDEX機制。
計算節點組件版本為5.4.19,發布日期早於2024-07-10之前,無自動FORCE INDEX機制;發布日期不早於2024-07-10,預設開啟自動FORCE INDEX機制。
計算節點組件版本高於5.4.19,預設開啟自動FORCE INDEX機制。
注意事項
對於只涉及單表、廣播表的查詢,不會觸發自動FORCE INDEX。
對於下推到儲存節點的多表關聯物理SQL,不會觸發自動FORCE INDEX。
對於下推到單分區的查詢,不會觸發自動FORCE INDEX。
局部索引選擇(local index selection)的優先順序從高到低,如下所示:
手動FORCE INDEX。
自動FORCE INDEX。
XPlan索引選擇。
儲存節點索引選擇。
原理
主鍵索引和唯一索引
主鍵索引和唯一索引自動FORCE INDEX的條件如下:
收集等值條件的列,收集到的列都是表中的原始列。
主鍵索引或唯一索引被收集到的列覆蓋。
普通二級索引
普通二級索引自動FORCE INDEX的條件如下:
剔除不能利用索引的條件後,剩餘條件僅包含等值條件。
收集等值條件與ORDER BY的列,收集到的列都是表中的原始列。
收集到的列被索引首碼覆蓋。
樣本
樣本表example,包含唯一索引UK與聯合索引LK,樣本如下:
CREATE TABLE `example` (
`a` int(11) NOT NULL,
`b` int(11) NOT NULL,
`c` int(11) NOT NULL,
`d` int(11) NOT NULL,
UNIQUE KEY `UK` (`a`, `b`),
KEY `LK` (`b`, `c`, `d`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4
PARTITION BY KEY(`a`)
PARTITIONS 4情境一:
收集到的列為(a,b),c,可以覆蓋索引UK,會自動執行FORCE INDEX(UK),樣本如下:
select * from example where (a,b) in ((1,2),((3,4))) and c = 1 order by dmysql> explain select * from example where (a,b) in ((1,2),((3,4))) and c = 1 order by d;
+------------------------+
| LOGICAL EXECUTIONPLAN
+------------------------+
| MergeSort(sort="d ASC")
| LogicalView(tables="example[p1,p4]", shardCount=2, sql="SELECT `a`, `b`, `c`, `d` FROM `example` AS `example` FORCE INDEX(UK) WHERE ((((`a`, `b`)) IN(?)) AND (`c` = ?)) ORDER BY `d`", pruningInfo="all size:2*2(part), pruning size:2") |
| HitCache:false
| Source:PLAN_CACHE
| TemplateId: 3148a498
+------------------------+情境二:
收集到的列為c,不可以覆蓋索引UK,不會自動執行FORCE INDEX(),樣本如下:
select * from example where (a+1,b) in ((1,2),((3,4))) and c = 1 order by dmysql> explain select * from example where (a+1,b) in ((1,2),((3,4))) and c = 1 order by d;
+------------------------+
| LOGICAL EXECUTIONPLAN
+------------------------+
| MergeSort(sort="d ASC")
| LogicalView(tables="example[p1,p2,p3,p4]", shardCount=4, sql="SELECT `a`, `b`, `c`, `d` FROM `example` AS `example` WHERE (((((`a` + ?), `b`)) IN(?)) AND (`c` = ?)) ORDER BY `d`") |
| HitCache:false
| Source:PLAN_CACHE
| TemplateId: 5ad46a6e
+------------------------+情境三:
收集到的列為b,c,可以被索引LK首碼匹配,會自動執行FORCE INDEX(LK),樣本如下:
select * from example where (b) in (1,2) and a > b order by cmysql> explain select * from example where (b) in (1,2) and a > b order by c;
+------------------------+
| LOGICAL EXECUTIONPLAN
+------------------------+
| MergeSort(sort="c ASC")
| LogicalView(tables="example[p1,p2,p3,p4]", shardCount=4, sql="SELECT `a`, `b`, `c`, `d` FROM `example` AS `example` FORCE INDEX(LK) WHERE ((`a` > `b`) AND (`b` IN(?))) ORDER BY `c`") |
| HitCache:false
| Source:PLAN_CACHE
| TemplateId: 3a4124bd
+------------------------+情境四:
剔除不能利用索引的條件後,剩餘條件包含非等值條件c>1,不會自動執行FORCE INDEX,樣本如下:
select * from example where (b) in (1,2) and c > 1 order by dmysql> explain select * from example where (b) in (1,2) and c > 1 order by d;
+------------------------+
| LOGICAL EXECUTIONPLAN
+------------------------+
| MergeSort(sort="d ASC")
| LogicalView(tables="example[p1,p2,p3,p4]", shardCount=4, sql="SELECT `a`, `b`, `c`, `d` FROM `example` AS `example` WHERE ((`b` IN(?)) AND (`c` > ?)) ORDER BY `d`") |
| HitCache:false
| Source:PLAN_CACHE
| TemplateId: f01b447f
+------------------------+