Oracle行內鏈接不會引起USER_TABLES中CHAIN_CNT值變化

来源:http://www.cnblogs.com/kerrycode/archive/2016/07/10/5657153.html
-Advertisement-
Play Games

前幾天和群里網友討論一個關於行內鏈接(intra-block chaining)的問題,問題非常有意思,恰好今天有空,順便整理了一下這些知識點。 問題描述:下麵SQL,創建一個超過255列的表(實際為256列),然後插入幾條數據,然後對錶做ANALYZE分析過後,但是發現user_tables的CH... ...


    前幾天和群里網友討論一個關於行內鏈接(intra-block chaining)的問題,問題非常有意思,恰好今天有空,順便整理了一下這些知識點。

 

    問題描述:下麵SQL,創建一個超過255列的表(實際為256列),然後插入幾條數據,然後對錶做ANALYZE分析過後,但是發現user_tables的CHAIN_CNT欄位值為0,chained_rows表中沒有記錄,為什麼會這樣

declare
v_sql varchar2(32767) ;
begin
v_sql := 'create table t_chain1 ( ' ;
for i in 1..256 loop
v_sql := v_sql || 'id'||i||' number,' ;
end loop ;
v_sql := rtrim(v_sql, ',') || ')';
execute immediate v_sql;
end ;
/
 
insert into t_chain1(id256) values(1);
insert into t_chain1(id256) values(2);
insert into t_chain1(id256) values(3);
commit;
 
 
 
analyze table t_chain1 list chained rows;
analyze table t_chain1 compute statistics;
 
 
 
SQL> select table_name, num_rows, chain_cnt, avg_row_len from user_tables
  2  where table_name='T_CHAIN1';
 
TABLE_NAME                       NUM_ROWS  CHAIN_CNT AVG_ROW_LEN
------------------------------ ---------- ---------- -----------
T_CHAIN1                                3          0         267
 
SQL> select * from chained_rows;
 
no rows selected

clip_image001

 

在分析這個問題前,我們要先瞭解一下Oracle資料庫當中的Row Migration (行遷移) & Row Chaining (行鏈接)概念:

    當表中一行的數據不能在一個數據block中放入的時候,這個時候就會發生兩種情況,一種是行鏈接(Row Chaining),另外一種就是行遷移(Row Migration)了。

   行鏈接產生在第一次插入數據的時候如果一個block不能存放一行記錄的情況下。這種情況下,Oracle將使用鏈接一個或者多個在這個段中保留的block存儲這一行記錄,行鏈接比較容易發生在比較大的行上,例如行上有LONG、LONG RAW、LOB等數據類型的欄位,這種時候行鏈接是不可避免的會產生的。

   當一行記錄初始插入的時候事可以存儲在一個block中的,由於更新操作導致行長增加了,而block的自由空間已經完全滿了,這個時候就產生了行遷移。在這種情況下,Oracle將會遷移整行數據到一個新的block中(假設一個block中可以存儲下整行數據),Oracle會保留被遷移行的原始指針指向新的存放行數據的block,這就意味著被遷移行的ROW ID是不會改變的。

 

當發生了行遷移或者行鏈接,對這行數據操作的性能就會降低,因為Oracle必須要掃描更多的block來獲得這行的信息

row chain:When a row is too large to fit into any block, row chaining occurs. In this case, the Oracle devide the row into smaller chunks. each chunk is stored in a block along with the necessary poiters to retrive and assemble the entire row.

row migration:when a row is to be updated and it cannot find the necessary free space in its block, the Oracle will move the entire row into a new block and leave a pointer from the orginal block to the new location. This process is called row migration.

 

那麼現在回到這個問題,我們先來看看表t_chain1的rowid,以及對應的文件號等信息:

select dbms_rowid.rowid_object(rowid)       obj#  ,
       dbms_rowid.rowid_relative_fno(rowid) rfile#,
       dbms_rowid.rowid_block_number(rowid) block#,
       dbms_rowid.rowid_row_number(rowid)   row#
from t_chain1 ;

clip_image002

 

我們看到這三條記錄對應的行數據在BLOCK中的相對位置為1,3,5,那麼說明當表的欄位個數超過255時,是發生了行內鏈接的,關於這個,我們繼續回顧一下行片段(row pieces)和行內鏈接(intra-block chaining)等概念

Row Format and Size

Oracle stores each row of a database table containing data for less than 256 columns as one or more row pieces. If an entire row can be inserted into a single data block, then Oracle stores the row as one row piece. However, if all of a row's data cannot be inserted into a single data block or if an update to an existing row causes the row to outgrow its data block, then Oracle stores the row using multiple row pieces. A data block usually contains only one row piece for each row. When Oracle must store a row in more than one row piece, it is chained across multiple blocks.

When a table has more than 255 columns, rows that have data after the 255th column are likely to be chained within the same block. This is called intra-block chaining. A chained row's pieces are chained together using the rowids of the pieces. With intra-block chaining, users receive all the data in the same block. If the row fits in the block, users do not see an effect in I/O performance, because no extra I/O operation is required to retrieve the rest of the row.

Each row piece, chained or unchained, contains a row header and data for all or some of the row's columns. Individual columns can also span row pieces and, consequently, data blocks. Figure 5-3 shows the format of a row piece:

clip_image003

 

這裡面介紹了行內鏈接(intra-block chaining)概念,當一個表的列超過255列,ORACLE會把行記錄分成兩個或多個行片段(row piece),一個row piece包含255個欄位,如果表中有312個欄位,那麼就會有三個行片段(row piece), 行內鏈接(intra-block chaining)只是多個行片段(row piece)通過rowid串聯起來,這也是上面測試案例,你看到的對應rowid返回該行數據在BLOCK中的相對位置對應是1、3、5 ,而不是1、2、3的原因,因為行內鏈接(intra-block chaining)發生的同一個塊內(block),所以它並不會產生額外的IO操作,也就是說不影響IO(當然這個要看你如何理解)。那麼我使用alter system dump 來看看行在塊裡面的信息吧

clip_image004

 

去$ORACLE_BASE下麵的udmp找到對應的trc文件,我實驗中生成的文件為scm2_ora_20850.trc

clip_image005

clip_image006

cc:表示列數,fb:H是指行記錄的頭,L是指行記錄的最後一列,F是指行記錄的第一列. 實驗結果跟理論是一致的。到這裡似乎一直沒有回到我們的問題來,那麼我們先來看看官方文檔對AVG_ROW_LEN的解釋:

 

Number of rows in the table that are chained from one data block to another, or which have migrated to a new block, requiring a link to preserve the old ROWID

註意我標記為紅色的部分,顯然AVG_ROW_LEN記錄的是發生了行鏈接或行遷移的行數,要麼是數據從一個block遷移到另外一個block,要麼是數據從一個block鏈接到另外一個block。而行內鏈接(intra-block chaining)是發生在同一個block內的,所以這裡實驗產生的行內鏈接並不會記錄到AVG_ROW_LEN裡面,所以這就解釋了AVG_ROW_LEN為0,chained_rows沒有記錄的原因。

下麵我們來構造一個行鏈接的案例,如下所示,新建表t_chain,使其一行的記錄無法插入到一個block裡面,那麼當插入的時候,就會產生行鏈接,此時對錶做ANALYZE分析過後,但是發現user_tables的CHAIN_CNT欄位值不為0了,chained_rows表中也會有相關記錄

declare
v_sql varchar2(32767) ;
begin
v_sql := 'create table t_chain ( ' ;
for i in 1..256 loop
v_sql := v_sql || 'id'||i||' char(36),' ;
end loop ;
v_sql := rtrim(v_sql, ',') || ')';
execute immediate v_sql;
end ;
/
 
declare
v_sql varchar2(32767) ;
begin
v_sql := 'insert into t_chain select ' ;
for i in 1..255 loop
v_sql := v_sql || '''it is only test'',' ;
end loop ;
v_sql := v_sql || '''it is only test'' from dual; commit;';
dbms_output.put_line( v_sql); --將生成的腳本執行2次
 
end ;
/
 
 
SQL> analyze table t_chain list chained rows;
 
Table analyzed.
 
SQL> analyze table t_chain compute statistics;
 
Table analyzed.
 
SQL>  select table_name, num_rows, chain_cnt, avg_row_len from user_tables
  2  where table_name='T_CHAIN' ;
 
TABLE_NAME                       NUM_ROWS  CHAIN_CNT AVG_ROW_LEN
------------------------------ ---------- ---------- -----------
T_CHAIN                                 2          2        9481
 
SQL> select count(1) from chained_rows;
 
  COUNT(1)
----------
         2
 
SQL> select * from chained_rows;
 
OWNER_NAME   TABLE_NAME   CLUSTER_NAME   PARTITION_NAME  SUBPARTITION_NAME   HEAD_ROWID      ANALYZE_T
----------- ------------ --------------- -------------- ----------------- ------------------ ---------
SYS             T_CHAIN                                       N/A          ACOhqAABAAAVMLAAA 10-JUL-16
SYS             T_CHAIN                                       N/A          AACOhqAABAAAVMNAAA 10-JUL-16
 
SQL> 

clip_image007

 

 

參考資料:

https://docs.oracle.com/cd/B19306_01/server.102/b14237/statviews_2105.htm#REFRN20286

http://docs.oracle.com/cd/B19306_01/server.102/b14220/schema.htm#i4383

http://docs.oracle.com/cd/B28359_01/server.111/b28318/schema.htm#CNCPT1129

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在RHEL5.x版本下麵,在添加磁碟分區等操作後,一直使用partproble命令使內核重新讀取分區表信息,從而不用重新啟動。但是最近在RHEL 6(Red Hat Enterprise Linux Server release 6.6 (Santiago))下,使用partprobe出現錯誤。 [... ...
  • Kubernetes為Google開源的容器管理框架,提供了 Docker容器的誇主機、集群管理、容器部署、高可用、彈性伸縮 等一系列功能;Kubernetes的設計目標包括使容器集群任意時刻都處於用戶期望的狀態,因而建立了一整套集群管理機制:容器自動重啟、自動備份、容器自動伸縮等;Kubernet ...
  • 我會用幾篇博客總結一下在Linux中進程之間通信的幾種方法,我會把這個開頭的摘要部分在這個系列的每篇博客中都打出來 進程之間通信的方式 管道 消息隊列 信號 信號量 共用存儲區 套接字(socket) 進程間通信(三)—信號量傳送門:http://www.cnblogs.com/lenomirei/ ...
  • 一. 準備工作 1. 需要一個Linux宿主系統,例如早先版本的 LFS,Ubuntu/Fedora,SuSE 或者是在你的架構上可以運行的其它發行版 二. LFS目標架構 LFS主要支持 AMD/Intel 的 x86(32 位)和 x86_64(64 位) 的目標架構。另外,做一些更改可以讓LF ...
  • 1. 修改官方軟體庫列表 編輯/etc/apt/sources.list,註釋掉原有內容,然後添加下述內容。 2. 執行更新命令並重啟 參考鏈接: 1. Kali Linux, Rolling Edition Released – 2016.1 ...
  • Apache + MySql + Php. 1、安裝Apache Apache可以用下麵的命令來安裝 sudo apt-get install apache2 Apache預設路徑是/var/www/ 其配置文件路徑為: /etc/apache2/ 可以通過:sudo nano /etc/apach ...
  • 郵件告警發現海外工廠一Linux伺服器連接不上,DPA(Database Performance Analyzer)系統也發現其出現問題,ping這台伺服器發現網路不通,聯繫不到當地系統管理員,郵件咨詢後,這個系統管理員也發現有問題,直接重啟了,事後檢查發現日誌message裡面,從10:10分開始... ...
  • redis的list類型其實就是一個每個子元素都是string類型的雙向鏈表。所以[lr]push和[lr]pop命令的演算法時間複雜度都是O(1)。另外list會記錄鏈表的長度。所以llen操作也是O(1).鏈表的最大長度是(2的32次方-1)。我們可以通過push,pop操作從鏈表的頭部或者尾部添 ...
一周排行
    -Advertisement-
    Play Games
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...