再談記錄超長

yanhengdoudou發表於2020-04-20

 

  再談記錄超長

  現象描述

我們知道,在達夢資料庫中,一般情況,一行記錄的長度,不能超過頁大小的一半。也就是如果我們在初始化資料庫的時候,如果選擇的頁大小是8K ,那麼我們一個表,一行記錄的所有欄位加起來,不能超過4K

如果超過,就會碰到無法插入,或者無法update 的事情,報錯為:記錄超長。

當我們選擇的頁大小為16K 或者32K ,同理(也就是限制為8K 或者16K )。

備註:大欄位不參與上述計算。

 

我們前面已經介紹過,對於如果確實要存取超過限制長度的情況,也是有處理辦法的:對這個表啟用超長列:alter table  username.tablename  enable using long row;

備註:以前往往需要選擇一個比較長的字元型別欄位,更改為CLOB ,當有超長列這個功能後,就不需要用這種對應用不有好的方式了(因為調整欄位型別,可能涉及到讀取改欄位的程式碼需要修改調整。)

 

問題

誠如上面說的,但是有時候,我們執行某個update 或者insert 的時候, 明明對應行的記錄,沒有超過一半的頁大小,或者也已經啟用了超長列了,為什麼還會碰到 記錄超長的錯誤呢?

 

 

處理方法

使用環境

資料庫版本:DM Database Server x64 V8.1.0.156-Build(2019.05.05-106384)SEC

環境:個人pc 環境

  構造實驗

  問題場景構建

 

drop table test2 ;

create table test2 ( v1 varchar , v2 varchar , v3 varchar ) ;

alter table test2 enable using long row ;

 

create index idx_test2_2 on test2 ( v3 );

 

insert into test2 values ( '' , '' , dbms_random . string ( 'x' , 1543 )); -- 成功

insert into test2 values ( '' , '' , dbms_random . string ( 'x' , 1544 )); -- 記錄超長

update test2 set v3=dbms_random . string ( 'x' , 1544 ) where v1 is null ; -- 記錄超長

  一次解析:實驗1,- 索引長度測試

drop   table test1 ;

create   table test1 (v1  varchar );

create   index idx_1  on test1 (v1 );

 

declare

int ; int ;

begin

for  rs  in 1 ..3000  LOOP

b=rs ;

declare

begin

insert   into test1  values (dbms_random . string ( 'x' , rs ));

exception   when others  then

 raise_application_error  ( -20001 , substr (  a|| '--' ||rs|| 執行失敗 , ' ||SQLCODE|| ' ' ||SQLERRM|| ' ' ||dbms_utility . format_error_backtrace   ,  1 ,  400 ));

end ;

end   loop ;

end ;

 

--1544  執行失敗 , -2665  記錄超長  -2665[-20001]: anonymous block line 8 

 

   二次解析:完全例項

select page (); --8192

 

drop table test1 ;

create table test1 ( v1 varchar , v2 varchar , v3 varchar );

 

insert into test1 values (

dbms_random . string ( 'x' , 4000 ), '' , ''

); -- 記錄超長

 

declare

a int ;

begin

for rs in 1 .. 1000 LOOp

declare begin

a=rs ;

insert into test1 values (

dbms_random . string ( 'x' , 3500+rs ), '' , ''

); -- 記錄超長

exception when others then

 raise_application_error ( -20001 , substr ( a|| ' 執行失敗 , ' ||SQLCODE|| ' ' ||SQLERRM|| ' ' ||dbms_utility . format_error_backtrace  , 1 , 400 ));

end ;

end loop ;

end ;

-- 380 執行失敗 , -2665 記錄超長 -2665[-20001]: anonymous block line 9

-- 3880 就無法插入了

 

insert into test1 values (

dbms_random . string ( 'x' , 3880 ), '' , ''

); -- 記錄超長

 

 

insert into test1 values (

dbms_random . string ( 'x' , 3879 ), '' , ''

); -- 成功

 

alter table test1 enable using long row ;

 

insert into test1 values (

dbms_random . string ( 'x' , 3880 ), '' , ''

); -- 成功

 

insert into test1 values (

dbms_random . string ( 'x' , 3880 ), '' , ''

); -- 成功

 

insert into test1 values (

dbms_random . string ( 'x' , 3880 ), dbms_random . string ( 'x' , 1544 ), dbms_random . string ( 'x' , 1543 )

); -- 成功

 

create index idx_test1_1 on test1 ( v2 ); -- 記錄超長

 

create index idx_test1_2 on test1 ( v3 ); -- 成功

 

  總結

 

其實,就是索引有長度限制。字元數通過varchar 型別,限制為1543 個字元,實際上,一個索引結構的最大長度,可能是3000 個位元組,去掉一些儲存結構本身佔用的空間,結果就如上測試。

 

如果我們要解決【問題場景構建】中的問題,需要刪除索引——也就是說,不要在過長的列上建立索引——一個索引涉及到的所有列,總長度不能超過設定的長度。

 

至少目前看起來,在過於長的列上,建立的索引,應用需要的程度很低。也就是說,該限制在達夢的正常使用過程中,暫時未發現會造成實質性影響。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69949798/viewspace-2683276/,如需轉載,請註明出處,否則將追究法律責任。

相關文章