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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...