全局索引和本地索引分析
有同行问到了全局索引和本地索引如何选择,全局索引可以分区也可以不分区,而本地索引只包含各自分区的数据。 本地索引是分区的,而且是根据分区表的分区键值来对应,就是分区表的每个分区都有对应的分区索引,而全局索引可以分区也可以不分区,全局索引对应
有同行问到了全局索引和本地索引如何选择,全局索引可以分区也可以不分区,而本地索引只包含各自分区的数据。
本地索引是分区的,而且是根据分区表的分区键值来对应,就是分区表的每个分区都有对应的分区索引,而全局索引可以分区也可以不分区,全局索引对应的表可以是分区表也可以不是分区表。
比如这里t_global01是heap table并不是partition table
SQL> create table t_global01 as select * from dba_objects;
Table created.
SQL> CREATE INDEX index_t_objid
2 ON t_global01 (object_id) global
3 PARTITION BY RANGE(object_id)
4 (PARTITION p1 VALUES LESS THAN(10000),
5 PARTITION p2 VALUES LESS THAN(20000),
6 PARTITION pmax VALUES LESS THAN(MAXVALUE));
Index created.
索引又可以分为前缀索引和非前缀索引,前缀索引是指索引的分区键包含在索引中,并且是索引的前导列,而非前缀索引则是分区键不在索引中或者不是索引的前导列,本地索引可以建立前缀索引和非前缀索引,而全局索引只能建立前缀索引。
SQL> create table t_local01 partition by range(object_id)
2 (partition p1 values less than(10000),
3 partition p2 values less than(20000),
4 partition p3 values less than(30000),
5 partition p4 values less than(40000),
6 partition p5 values less than(maxvalue))
7 as select * from dba_objects;
Table created.
建立本地的前缀索引
SQL> CREATE INDEX index_t_pre01 on t_local01(object_id,object_name) local;
Index created.
建立本地的非前缀索引
SQL> CREATE INDEX index_t_nonpre01 on t_local01(object_name) local;
Index created.
全局索引不允许建立非前缀索引
SQL> create index ind_t_objid_nonpre on t_local01(object_id) global
2 partition by range(data_object_id)
3 (partition p1 values less than(10000),
4 partition pmax values less than(maxvalue));
partition by range(data_object_id)
*
ERROR at line 2:
ORA-14038: GLOBAL partitioned index must be prefixed
分区表的全局索引可能会因为分区表的ddl而导致全局索引失效,这个需要我们特别注意,一般来说oltp建立全局索引,而在olap系统建立本地索引。
Partitioned Indexes: Global, Local, Prefixed and Non-Prefixed (文档 ID 69374.1)
To illustrate the usefulness of global indexes, imagine that we have a large
fact table partitioned on a DATE column. We frequently need to search the table
on a VARCHAR2 column (VCOL) which is not part of the table's partition key.
Assume that there are currently 12 partitions in the table.
We could use 2 possible methods:
A local non-prefixed index on VCOL:
| |
------- -------
| | (10 more | |
Values: A.. Z.. partitions here) A.. Z..
Or a global prefixed index on VCOL:
| |
------- -------
| | (10 more | |
Values: A.. D.. partitions here) T.. Z..
A global prefixed index would usually be the best choice for a unique index on
our example VCOL column. For nonunique indexes, the issue is whether we can use
parallel index searches (local non-prefixed) or whether we need a serial search,
even at the expense of the greater maintenance problems of global indexes.
这里提出了对于唯一列建立全局索引较合适
Common Questions on Indexes on Partitioned Table (文档 ID 1481609.1)记录了local index和global index的适用特点
What are the performance implications of local indexes
Partition elimination/pruning during SQLs against the partitioned table with predicate on the partition key (prefixed more often allows for partition elimination than non prefixed).
这里提出了如果查询条件中有分区键,建立本地索引可以让分区裁剪生效(前缀索引通常比非前缀索引更容易发生分区裁剪)
Non prefixed local index is useful if it is important to have quick access according to a column which is not the partition key (e.g. look up for value account_number column, hence the account_number is placed as a leading column of the index), while it is also important to have the index equipartitioned with the table e.g. to support the time interval for rolling out old data and rolling in new data (e.g. partition key is time_id column, rolling out/in data is done by partition maintenance commands). This scenario often happens in historical databases.
而非前缀索引通常在查询中没有分区键过滤时比较适用。
下面来通过测试来看看上面文章提供的结论:
SQL> create table tab01
2 partition by range(object_id)
3 (partition p1 values less than(10000),
4 partition p2 values less than(20000),
5 partition p3 values less than(30000),
6 partition p4 values less than(40000),
7 partition p5 values less than(maxvalue))
8 as
9 select * from dba_objects;
Table created.
SQL> create index ind_type_local_pre on tab01(object_id,object_type) local;
Index created.
SQL> create index ind_type_local_nonpre on tab01(object_type) local;
Index created.
SQL> analyze table tab01 compute statistics;
Table analyzed.
上面已经建立了前缀和非前缀的本地索引,然后如果我们的查询中没有分区键,那么看看两个索引的实用性
SQL> select /*+index(tab01 ind_type_local_nonpre)*/* from tab01 where object_typ
e='INDEX';
1726 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 4022647995
--------------------------------------------------------------------------------
--------------------------------------------
| Id | Operation | Name | Rows | Byt
es | Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------
--------------------------------------------
| 0 | SELECT STATEMENT | | 1481 | 1
27K| 74 (0)| 00:00:01 | | |
| 1 | PARTITION RANGE ALL | | 1481 | 1
27K| 74 (0)| 00:00:01 | 1 | 5 |
| 2 | TABLE ACCESS BY LOCAL INDEX ROWID| TAB01 | 1481 | 1
27K| 74 (0)| 00:00:01 | 1 | 5 |
|* 3 | INDEX RANGE SCAN | IND_TYPE_LOCAL_NONPRE | 1481 |
| 10 (0)| 00:00:01 | 1 | 5 |
--------------------------------------------------------------------------------
--------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("OBJECT_TYPE"='INDEX')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
353 consistent gets
0 physical reads
0 redo size
87737 bytes sent via SQL*Net to client
1757 bytes received via SQL*Net from client
117 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1726 rows processed
SQL> select /*+index(tab01 ind_type_local_pre)*/* from tab01 where object_type='
INDEX';
1726 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1706313756
--------------------------------------------------------------------------------
-----------------------------------------
| Id | Operation | Name | Rows | Bytes
| Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------
-----------------------------------------
| 0 | SELECT STATEMENT | | 1481 | 127K
| 198 (1)| 00:00:03 | | |
| 1 | PARTITION RANGE ALL | | 1481 | 127K
| 198 (1)| 00:00:03 | 1 | 5 |
| 2 | TABLE ACCESS BY LOCAL INDEX ROWID| TAB01 | 1481 | 127K
| 198 (1)| 00:00:03 | 1 | 5 |
|* 3 | INDEX FULL SCAN | IND_TYPE_LOCAL_PRE | 1481 |
| 176 (1)| 00:00:03 | 1 | 5 |
--------------------------------------------------------------------------------
-----------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("OBJECT_TYPE"='INDEX')
filter("OBJECT_TYPE"='INDEX')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
521 consistent gets
174 physical reads
0 redo size
87699 bytes sent via SQL*Net to client
1757 bytes received via SQL*Net from client
117 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1726 rows processed
这里看来对于本地索引,在查询条件中没有分区键时非前缀索引比较实用。
而如果有分区键的查询,本地索引是可以走分区裁剪的
SQL> select /*+index(tab01 ind_type_local_pre)*/* from tab01 where object_type='
INDEX' and object_id
920 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 4238522555
--------------------------------------------------------------------------------
-----------------------------------------
| Id | Operation | Name | Rows | Bytes
| Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------
-----------------------------------------
| 0 | SELECT STATEMENT | | 281 | 21075
| 34 (0)| 00:00:01 | | |
| 1 | PARTITION RANGE SINGLE | | 281 | 21075
| 34 (0)| 00:00:01 | 1 | 1 |
| 2 | TABLE ACCESS BY LOCAL INDEX ROWID| TAB01 | 281 | 21075
| 34 (0)| 00:00:01 | 1 | 1 |
|* 3 | INDEX RANGE SCAN | IND_TYPE_LOCAL_PRE | 281 |
| 30 (0)| 00:00:01 | 1 | 1 |
--------------------------------------------------------------------------------
-----------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("OBJECT_TYPE"='INDEX' AND "OBJECT_ID" filter("OBJECT_TYPE"='INDEX')
Statistics
----------------------------------------------------------
244 recursive calls
0 db block gets
244 consistent gets
0 physical reads
0 redo size
45241 bytes sent via SQL*Net to client
1163 bytes received via SQL*Net from client
63 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
920 rows processed
SQL> select /*+index(tab01 ind_type_local_nonpre)*/* from tab01 where object_typ
e='INDEX' and object_id
920 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1322437935
--------------------------------------------------------------------------------
--------------------------------------------
| Id | Operation | Name | Rows | Byt
es | Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------
--------------------------------------------
| 0 | SELECT STATEMENT | | 281 | 210
75 | 21 (0)| 00:00:01 | | |
| 1 | PARTITION RANGE SINGLE | | 281 | 210
75 | 21 (0)| 00:00:01 | 1 | 1 |
| 2 | TABLE ACCESS BY LOCAL INDEX ROWID| TAB01 | 281 | 210
75 | 21 (0)| 00:00:01 | 1 | 1 |
|* 3 | INDEX RANGE SCAN | IND_TYPE_LOCAL_NONPRE | 281 |
| 1 (0)| 00:00:01 | 1 | 1 |
--------------------------------------------------------------------------------
--------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("OBJECT_TYPE"='INDEX')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
182 consistent gets
0 physical reads
0 redo size
45241 bytes sent via SQL*Net to client
1163 bytes received via SQL*Net from client
63 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
920 rows processed
这里我们看出执行计划中都出现了PARTITION RANGE SINGLE单个分区扫描(pstart和pstop都是1),这个是因为执行计划的INDEX RANGE SCAN索引范围扫描时pstart 1和pstop 1,此时索引扫描就只会扫描指定的索引分区,这个也就是索引的分区裁剪,当然还有表的分区裁剪,关于分区裁剪的内容小鱼后面有时间会列出来单独讨论。
而如果是全局索引,索引默认不分区,所以也就无法发生索引的分区裁剪:
SQL> drop index ind_type_local_nonpre;
Index dropped.
SQL> create index ind_type_global on tab01(object_type) global;
Index created.
SQL> select /*+index(tab01 ind_type_global)*/* from tab01 where object_type='IND
EX' and object_id
920 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 3954671853
--------------------------------------------------------------------------------
--------------------------------------
| Id | Operation | Name | Rows | Bytes | C
ost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------
--------------------------------------
| 0 | SELECT STATEMENT | | 281 | 21075 |
69 (0)| 00:00:01 | | |
|* 1 | TABLE ACCESS BY GLOBAL INDEX ROWID| TAB01 | 281 | 21075 |
69 (0)| 00:00:01 | 1 | 1 |
|* 2 | INDEX RANGE SCAN | IND_TYPE_GLOBAL | 1481 | |
5 (0)| 00:00:01 | | |
--------------------------------------------------------------------------------
--------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_ID" 2 - access("OBJECT_TYPE"='INDEX')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
185 consistent gets
6 physical reads
0 redo size
45241 bytes sent via SQL*Net to client
1163 bytes received via SQL*Net from client
63 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
920 rows processed
What are the performance implications of global indexes?
Global index can be useful where rapid access, data integrity, and availability are important. In an OLTP system, a table may be partitioned by one key, for example, the employees.department_id column, but an application may need to access the data with many different keys, for example, by employee_id or job_id. Global indexes can be useful in this scenario as global indexes are prefixed and can provide better performance than local nonprefixed indexes because they minimize the number of index partition probes (cf. local prefixed more often allows for partition elimination than non prefixed mentioned in the previous section).
全局索引多用于OLTP系统,可以快速的返回查询的数据,特别适用于查询条件中不包含分区键的查询,这种情况全局索引相比本地索引更加高效。
Global indexes are harder to manage than local indexes. At partition maintenance of the table, all partitions of a global index are affected.
这里提出全局索引难以维护,如果分区修改了,所有分区的索引都会影响
Partition elimination/pruning during SQLs against the partitioned table: prefixed - always allows for partition elimination.
同样全局索引也是可以发生分区裁剪的
SQL> create table t_global01 as select * from dba_objects;
Table created.
SQL> CREATE INDEX index_t_objid
2 ON t_global01 (object_id) global
3 PARTITION BY RANGE(object_id)
4 (PARTITION p1 VALUES LESS THAN(10000),
5 PARTITION p2 VALUES LESS THAN(20000),
6 PARTITION pmax VALUES LESS THAN(MAXVALUE));
Index created.
SQL> select * from t_global01 where object_id
9568 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1223163610
--------------------------------------------------------------------------------
------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CP
U)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------
------------------------------
| 0 | SELECT STATEMENT | | 9194 | 897K| 177 (
0)| 00:00:03 | | |
| 1 | PARTITION RANGE SINGLE | | 9194 | 897K| 177 (
0)| 00:00:03 | 1 | 1 |
| 2 | TABLE ACCESS BY INDEX ROWID| T_GLOBAL01 | 9194 | 897K| 177 (
0)| 00:00:03 | | |
|* 3 | INDEX RANGE SCAN | INDEX_T_OBJID | 9194 | | 43 (
0)| 00:00:01 | 1 | 1 |
--------------------------------------------------------------------------------
------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("OBJECT_ID"
这里看出也发生了所谓的分区裁剪,index range scan的pstart和pstop都是1,说明是扫描了索引的一个分区,这也和上面partition range single相对应(出现partition range single并不一定表示该表是分区表,有可能有分区的索引)
The hash index partitioning can improve performance of indexes where a small number leaf blocks in the index have high contention in multiuser OLTP environment. In some OLTP applications, index insertions happen only at the right edge of the index. This situation could occur when the index is defined on monotonically increasing columns (e.g. column value is populated by a sequence). In such situations, the right edge of the index becomes a hotspot because of contention for index pages, buffers, latches for update, and additional index maintenance activity, which results in performance degradation.
这里提出了一个hash index partition,在高并发情况下,索引的数据会不停往右边倾斜(比如列是序列填充时),这种情况下索引右边叶块会成为热点块,造成大量的buffer latches竞争和额外的维护(比如索引分裂)而导致性能下降。
关于本地索引和全局索引小鱼也没有较多的实战案例,个人而言小鱼维护的大多是OLTP系统,所以一般都是建立的全局索引,可以参考以下建立:
Global index和local index适用范围
non-prefixed Local indexes特别适用于基于历史数据查询分析的数据库,在这样的数据库中,历史数据一般都是根据时间来分区的。
prefixed Local index适用于对分区主键进行索引,可以明显减少查询所搜索到的分区数目,极大的加快查询速度。
Global prefixed index适用于对非分区主键进行索引,特别对于唯一列的查询是比较适合建立全局索引的,但是Global pre- fixed index难以维护,任何对基表的分区信息的修改都会不可避免的导致索引的失效。
原文地址:全局索引和本地索引分析, 感谢原作者分享。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

如何在uniapp中實現資料統計和分析一、背景介紹資料統計和分析是行動應用開發過程中非常重要的一環,透過對使用者行為的統計和分析,開發者可以深入了解使用者的喜好和使用習慣,從而優化產品設計和使用者體驗。本文將介紹如何在uniapp中實現資料統計和分析的功能,並提供一些具體的程式碼範例。二、選擇合適的資料統計和分析工具在uniapp中實現資料統計和分析的第一步是選擇合

汽水音樂本地音樂怎麼添加?汽水音樂APP中可以添加自己喜愛的本地音樂,但是多數的小伙伴不知道如何添加本地音樂,接下來就是小編為用戶帶來的汽水音樂本地音樂添加方法圖文教程,有興趣的用戶快來一起看看吧!汽水音樂使用教學汽水音樂本地音樂怎麼添加1、先打開汽水音樂APP,主頁最下方【音樂】功能專區點擊;2、之後進入到播放頁面,點擊右下角【三個點】圖標;3、最後下方展開功能欄,選擇其中【下載】按鈕即可新增至本機音樂。

oracle索引類型有:1、B-Tree索引;2、位圖索引;3、函數索引;4、雜湊索引;5、反向鍵索引;6、局部索引;7、全域索引;8、網域索引;9、位圖連接索引;10、複合索引。詳細介紹:1、B-Tree索引,是一種自平衡的、可以有效率地支援並發操作的樹狀資料結構,在Oracle資料庫中,B-Tree索引是最常用的一種索引類型;2、位圖索引,是一種基於點陣圖演算法的索引類型等等。

標題:解析織夢CMS二級目錄打不開的原因及解決方案織夢CMS(DedeCMS)是一款功能強大的開源內容管理系統,被廣泛應用於各類網站建設中。然而,有時在搭建網站過程中可能會遇到二級目錄無法開啟的情況,這給網站的正常運作帶來了困擾。在本文中,我們將分析二級目錄打不開的可能原因,並提供具體的程式碼範例來解決這個問題。一、可能的原因分析:偽靜態規則配置問題:在使用

標題:騰訊主要的程式語言是否為Go:一項深入分析騰訊作為中國領先的科技公司,在程式語言的選擇上一直備受關注。近年來,有人認為騰訊主要採用Go作為主要的程式語言。本文將對騰訊主要的程式語言是否為Go進行深入分析,並給出具體的程式碼範例來支持這一觀點。一、Go語言在騰訊的應用Go是一種由Google開發的開源程式語言,它的高效性、並發性和簡潔性受到眾多開發者的喜

靜態定位技術的優勢與限制分析隨著現代科技的發展,定位技術已成為我們生活中不可或缺的一部分。而靜態定位技術作為其中的一種,具有其特有的優點與限制。本文將對靜態定位技術進行深入分析,以便更了解其應用現狀和未來的發展趨勢。首先,我們來看看靜態定位技術的優勢所在。靜態定位技術是透過對待定位物件進行觀測、測量和計算來實現位置資訊的確定。相較於其他定位技術,

解決方法有:1、檢查索引值是否正確:先確認你的索引值是否超出了陣列的長度範圍。數組的索引從0開始,所以最大索引值應該是數組長度減1;2、檢查循環邊界條件:如果是在循環中使用索引進行數組訪問,要確保循環的邊界條件正確;3、初始化數組:在在使用陣列之前,請確保陣列已經正確初始化;4、使用異常處理:在程式中可以使用異常處理機制來捕捉索引超出陣列界限的錯誤,並進行相應的處理。

哈醫大臨床藥學就業前景如何儘管全國就業情況不容樂觀,但藥科類畢業生仍有著良好的就業前景。整體來看,藥科類畢業生的供給量少於需求量,各醫藥公司和製藥廠是吸收這類畢業生的主要管道,製藥業對人才的需求也穩定成長。據介紹,近幾年藥物製劑、天然藥物化學等專業的研究生供需比甚至達到1∶10。臨床藥學專業就業方向:臨床醫學專業學生畢業後可在醫療衛生單位、醫學科研等部門從事醫療及預防、醫學科研等方面的工作。就業機會:醫藥代表、醫藥銷售代表、銷售代表、銷售經理、區域銷售經理、招募經理、產品經理、產品專員、護
