2014年5月22日 星期四

Oracle - 中文輸入 出現 ORA-01756: quoted string not properly terminated



今天使用 sqlplus 測試 insert資料時 ,出現了 ORA-01756: quoted string not properly terminated  錯誤


insert into test (name) values ('大家好');


什麼...... 左看右看我的括號也沒少怎麼會出錯呢,那把中文改成英文, sql 是可以執行沒問題的

看來是中文字的問題,原來是 Client 端 與 db 端 語系不同,我們來設一下Client 端 語系

1.查詢一下DB 端的語系設定

code

SQL> select userenv('language') from dual;

USERENV('LANGUAGE')
----------------------------------------------------
AMERICAN_AMERICA.UTF8


2.再來設定 Client 端語系
>export NLS_LANG=AMERICAN_AMERICA.UTF8




後來某天執行.sql 檔案時出現了

SP2-0734: unknown command beginning "嚜窺et SER..." - rest of line ignored.

從錯誤的訊息來看,好像不是SQL本身的問題

這時突然想到 .sql 檔編碼的問題

改成 UTF-8 編碼 檔首無BOM儲存,就可以成功執行囉。

2014年5月21日 星期三

Oracle 資料加密功能 - dbms_crypto


Oracle 在10G 之前必須使用DBMS_OFUSCATION_TOOLKIT 來做加密與解密,10GR2之後提供了 DBMS_CRYPTO 功能上更為強大。


DBMS_CRYPTO 除了一般資料類型外也有支援RAW、LOBS、大數據類型 BLOB與CLOB (Oracle 稱聲音與圖像也可以)。


可以使用以下的加密技術
Data Encryption Standard (DES), Triple DES (3DES, 2-key and 3-key)
Advanced Encryption Standard (AES)
MD5, MD4, and SHA-1 cryptographic hashes
MD5 and SHA-1 Message Authentication Code (MAC)


DBMS_CRYPTO 加密算法
ENCRYPT_DES :數據加密標準。分組密碼。使用56位密鑰長度。
ENCRYPT_3DES_2KEY :數據加密標準。分組密碼。經營一個塊上3次,2把鑰匙。 112位有效密鑰長度。
ENCRYPT_3DES :數據加密標準。經營一個塊上3倍。
ENCRYPT_AES128 :高級標準加密。使用128位的密鑰大小。
ENCRYPT_AES192 :高級標準加密。使用192位的密鑰大小。
ENCRYPT_AES256 :高級標準加密。使用256位的密鑰大小。
ENCRYPT_RC4 :被用於加密數據流,隨機生成的密鑰是唯一的。

 DBMS_CRYPTO 填充方式
PAD_PKCS5 :提供填充它符合PKCS#5:基於密碼的加密標準
PAD_NONE :不去填充。必須確保長度大小是8字元,否則會出現錯誤。
PAD_ZERO :用零去填充。

DBMS_CRYPTO 連接方式
CHAIN_ECB :電子密碼本。獨立加密每個明文塊。
CHAIN_CBC :密碼塊鏈接。明文或與以前的密文塊之前被加密。
CHAIN_CFB :密碼反饋。啟用加密數據的單位的塊大小。
CHAIN_OFB :輸出反饋。允許運行一個分組密碼作為同步流密碼。類似於CFB,除了前面的輸出塊的是n位被移動到數據隊列的等待要被加密的最右邊的位置上。

注意
.1.DBMS_CRYPTO 包在 sys 底下,所以使用前還需授權給user
    SQL> grant execute on sys.dbms_crypto to Test ;

2.另外varchar2 必須轉換成RAW 才能輸入 DBMS_CRYPTO,可以使用UTL_RAW 或者 UTL_I18N 來做類型轉換

範例
1. 加密 - 使用的是 AES128 加密算法 + pkcs5 填充方式 + CBC 連結

code

 set serveroutput on
 declare
     input_data varchar2(20) := 'HELLO WORL'; --資料

     E_type pls_integer := dbms_crypto.encrypt_aes128 +
                           dbms_crypto.pad_pkcs5 +
                           dbms_crypto.chain_cbc;
     E_key varchar2(16) := '0123456789123456'; --鑰匙密碼

     E_encval raw(2000);
  begin
     E_encval := dbms_crypto.encrypt(
                    src=>utl_i18n.string_to_raw(input_data,'AL32UTF8'),
                    typ=>E_type,
                    key=>utl_i18n.string_to_raw(E_key,'AL32UTF8'));
     dbms_output.put_line(E_encval);
  end;
  /

putout
0637CFF59C55D05E8D22A82B6CC49CF8



2.解密

code

 set serveroutput on
 declare

     Encryption_data raw(100) := hextoraw('0637CFF59C55D05E8D22A82B6CC49CF8');

     E_type pls_integer := dbms_crypto.encrypt_aes128 +
                           dbms_crypto.pad_pkcs5 +
                           dbms_crypto.chain_cbc;

     E_key varchar2(16) := '0123456789123456'; --要與加密的鑰匙密碼一致
     E_Decryption raw(200);
  begin
     E_Decryption := dbms_crypto.decrypt(
                    src=>Encryption_data,
                    typ=>E_type,
                    key=>utl_i18n.string_to_raw(E_key,'AL32UTF8'));

     dbms_output.put_line(utl_i18n.raw_to_char(E_Decryption));
  end;
  /

putout
HELLO WORL






2014年5月9日 星期五

Oracle - compress index 壓縮索引


Oracle 提供了很多優化DB的方式,像 compress 的功能 ,上次有解說 compress table ,這次我們來研究一下 compress index


1.首先建立一個測試的table

SQL> create table test_table1 as select * from dba_objects;

Table created.

SQL> insert into test_table1 select * from test_table1;

95850 rows created.

SQL> /

191700 rows created.

SQL> /

383400 rows created.

SQL> /

766800 rows created.

SQL> /

1533600 rows created.

SQL> /

3067200 rows created.

SQL> select count(*) from test_table1;

  COUNT(*)
----------
   6134400

約6百萬筆數

執行計畫( 因排版關係 則用截圖方式呈現

因為沒有 index 則 table full access ,consistent gets 87635


2.建立一般的index 

SQL> create index t_index on test_table1(object_type);

Index created.

SQL> set autot on

index 這次有使用到了,consisten gets 從87635 降到 1795 ,優化效果很顯著


查詢一下index size.

SQL> SELECT segment_name, header_block, bytes
  2    FROM dba_segments
  3   WHERE segment_name = 'T_INDEX';

SEGMENT_NAME             HEADER_BLOCK        BYTES
-----------------------------    ------------------                -------------
T_INDEX                                   174162                  142606336


index 大小約136MB


3.這次建立有壓縮的index (效果更強)

SQL> drop index t_index;

Index dropped.

SQL> create index t_index on test_table1(object_type) compress;

Index created.

使用了壓縮的index ,consistent gets 下降到1194,效果更驚人


查詢一下index size.

SQL> SELECT segment_name, header_block, bytes
      FROM dba_segments
     WHERE segment_name = 'T_INDEX';

SEGMENT_NAME             HEADER_BLOCK        BYTES
-----------------------------    ----------------------              -------------
T_INDEX                                   174162                   83886080

index 大小約 80MB


使用壓縮的index 跟沒有壓縮的index 比較

consistent gets 從 1795 降到 1194  -> 33.48 %
cost 從 2272 降到 1287  ->  43.35%
bytes 從 136MB 縮小到 80MB  -> 41.17%



難道compress  index 就真的這麼好用?!,會不會有其他狀況導致compress  index 的優點變成缺點呢,接下來我們在做更深入的實驗

1.建立一個測試 table 
   CREATE TABLE test_com 
      ( a    NUMBER, b  NUMBER) );

2.
  SQL> begin
  2    for i in 1..500000 loop
  3    insert into test_com values(mod(i,2),i);
  4    end loop;
  5    end;
  6    /

PL/SQL procedure successfully completed.

SQL> commit;

Commit complete.

SQL>


2. 查詢一下此 table 的欄位重覆的值狀況如何

SQL>  select count(distinct a),count(distinct b) from test_com;

COUNT(DISTINCTA)       COUNT(DISTINCTB)
------------------------      -----------------------------
               2                                    500000

SQL>

A欄位 裡面只有兩個不同的值,B欄位裡有 500000 都是不同的值


3.建立一般的 index ,並查看SIZE

SQL> create index test_com_idx1 on test_com(a);

Index created.

SQL> create index test_com_idx2 on test_com(b);

Index created.

SQL>

SQL> select segment_name , bytes/1024/1024 size_mb from dba_segments where segment_name like 'TEST_C
OM_%';

SEGMENT_NAME                               SIZE_MB
-----------------------------------            -----------------
TEST_COM_IDX1                                     8
TEST_COM_IDX2                                     9

SQL>

4.接著建立 有compress 的index ,並查看SIZE

SQL> drop index test_com_idx1;

Index dropped.

SQL> drop index test_com_idx2;

Index dropped.

SQL>
SQL> create index test_com_idx1 on test_com(a) compress;

Index created.

SQL> create index test_com_idx2 on test_com(b) compress;

Index created.

SQL>

SQL> select segment_name , bytes/1024/1024 size_mb from dba_segments where segment_name like 'TEST_C
OM_%';

SEGMENT_NAME                           SIZE_MB
-----------------------------------       ------------------
TEST_COM_IDX1                                 7
TEST_COM_IDX2                                13

這邊看到A欄位從未壓縮到壓縮 8MB > 7MB ,而B欄位卻從9MB 增大到13MB,index 對於table 重覆值較少的欄位還會增加更多空間來存放 prefix ,想啟動壓縮的功能卻讓size 變大


當然在很多種狀況下,並不能用同一招來打天下 ,所以這也是為什麼Oracle 提供了很多的解決方案

Oracle  官方 Concepts 裡的說明
Although key compression reduces the storage requirements of an index, it can increase the CPU time required to reconstruct the key column values during an index scan. It also incurs some additional storage overhead, because every prefix entry has an overhead of 4 bytes associated with it.


index compress
優點
1.值的重覆越多壓縮的效果越好,節省更多的空間(但要是欄位值重覆很少的話,建立index compress 其實也沒太大用處)
2.掃描的block 大幅減少 


缺點
1.index 更新時需要重新解壓縮 ->更新 ->壓縮,使用更多的執行時間與CPU
2.block 的爭用,當查詢的結果都集中再同一個block 時就會引起block 的爭用
3.bitmap index 不能壓縮



PS:
1.假如要對現有的index 啟動壓縮功能,可以利用rebuild index 重建index compress 或者解除壓縮功能

alter index T_INDEX rebuild compress;
alter index T_INDEX rebuild nocompress;


2.可以建立compress 的複合式index 

create index T_INDEX on test_com(a,b,c) compress1;  只壓縮第一個欄位
create index T_INDEX on test_com(a,b,c) compress2;   對前兩個欄位進行壓縮
create index T_INDEX on test_com(a,b,c) compress3;   對前三個欄位進行壓縮






















2014年5月8日 星期四

Oracle 11G RAC OCR 與 Vote disk 備份與還原



關於 RAC 最重要的 OCR與Voting 的備份與還原,DBA必須在遇到災難時去拯救還原

11G Oracle 預設是把OCR 與 Voting 放再同一個ASM disk group裡,也可以透過設定分開存放

以下是進行備份還原的步驟

1.查看OCR 相關訊息



2. 查看Voting 相關訊息 


3.查看OCR 備份資訊  (要連續執行RAC 4小時才會開啟自動備份)
下面有一個PROT-25的警告,於手動備份時失效

手動備份指令如下


4.用ms_backup 指令備份ASM disk group 的 Metadata,順便查看一下disk group資訊


5.進入ASM instance 順便備份ASM spfile (11G則必須使用 as sysasm 進入)



6.模擬 OCR 與 Voting 所在的硬碟毀損


7.查詢CRS狀態.......... 發現是正常的

8.不過在 check 硬碟時發出ERROR 訊息

查看一下log ,出現 Voting file 不見的ERROR訊息
2014-05-07 13:33:11.052: [    CSSD][2986240912]clssnmCompleteInitVFDiscovery: Completing initial voting file discovery
2014-05-07 13:33:11.052: [    CSSD][2986240912]clssnmvFindInitialConfigs: No voting files found
2014-05-07 13:33:11.052: [    CSSD][2986240912]clssnmCompleteVFDiscovery: Completing voting file discovery
2014-05-07 13:33:11.052: [    CSSD][2986240912]clssnmvVerifyCommittedConfigVFs: Insufficient voting files found, found 0 of 0 configured, needed 1 voting files


9.全部節點停掉CRS 服務



10.接下來開始恢復,先在節點1以獨占模式啟動CRS


11.重新建立ASM disk ,因為剛剛格式化硬碟所以先scandisk再createdisk

建立相同名稱的ASM DISK

查詢確定OCR 有建立


12. 進入 ASM instance 建立 ASM disk group


13.重新建好ASM disk group 後接著就可以還原OCR,使用-import 或 -restore 都可以


14.還需要恢復 ASM disk group 裡的spfile 

15.OCR恢復成功

16. 透過 crsctl replace votedisk 還原 Votedisk

操作到這邊有可能會發生以下錯誤

接著調整ASM 參數
調整完後重新啟動ASM instance 

在重新crsctl replace votedisk 還原 


17.查看恢復的Votedisk




18.退出獨佔模式  crsctl stop has -f 或 crsctl stop crs -f


19. 啟動兩節點的CRS

[root@node1 bin]# ./crsctl start has


20. 檢查CRS狀態- 恢復成功