mysql數據庫轉移到oracle的經歷


簡單說明一下情況,系統原本是LAMP的。現在要添加對oracle的支持,原來的mysql也同樣支持(通過配置選擇數據庫類型)。

 

第一步,表結構轉移到oracle,並掌握轉移的方法(方便給有二開的老客戶轉移);

第二步,表中數據轉移到oracle,主要掌握轉移方法,因為初始庫基本是空的數據;

第三步,在產品中用pdo跑通oracle(幸運的是本產品已經用的是pdo,只是沒有開通extension=php_pdo_oci.dll);

第四步,測試全產品,debug。

 

現進展到第一步,生成符合oracle語法的create table腳本。

雖然只是第一步,便困難重重。

1、字段類型的對應。

mysql oracle

longblob

blob

BLOB,但是對BLOB不太了解

longtext

mediumtext

沒有text類型,是不是應該用LONG?但是oracle的一個表中不能出現兩個LONG的字段。所以暫用VARCHAR2(2000)對應。
timestamp 暫用TIMESTAMP對應,但是oracle認識的timestamp是這樣的:"insert into JJJ values (14, '天ss天','18-8月-2016 10.42.12')";你寫2016-8-18 10:42:12是無法寫入oracle的。
datetime,類似於timestamp的格式 oracle的DATE類型,只認識'14-6月 -16',不認識'14-6月 -16 10:9:8',不認識2016-06-09。,所以暫用TIMESTAMP對應
date,mysql的date類型如:2016-06-09 oracle的DATE類型,只認識'14-6月 -16',不認識'14-6月 -16 10:9:8',不認識2016-06-09。
enum('3','2','1','0') oracle沒有枚舉型,暫用VARCHAR2(10)對應。其中10這個長度看情況調節。

zerofill

比如int(11) unsigned zerofill

zerofill,用0補充左邊不足的位數。int(11)就要補足11位。比如00000000001。

暫用NUMBER(11)對應。
float、decimal、double 比如"double(x,y)" => "NUMBER(x,y)",但需要驗證可行性。
decimal(10,0) decimal后面0位小數?暫用NUMBER(10,2)
varchar(0) 0代表啥?沒有長度。oracle不充許0長度的字段。暫用VARCHAR2(1)對應。
varchar(5000) oracle最大VARCHAR2(4000),4001都不行。暫用VARCHAR2(4000)對應。

 

2、表名和字段名的長度,oracle不能超過30,mysql無這個限制。

建表時,若超出,oracle會報錯   ORA-00972 identifier is too long

這種表有:

'icrm_refunds_trade_resend_goods',

'jingdong_qqg_trade',

'jingdong_trade',

'jumei_trade',

'openshop_refunds_trade_resend_goods',

'taobao_inventory_authorize_distributor',

'taobao_inventory_authorize_goods'

這些表中有的是表名過長,有的是字段名過長。

 

3、字段默認值問題。

MySQL創建表時,如果某字段定義為NOT NULL,並且沒有明確定義default值,則insert時可以不填該字段,mysql會自動給它填一個0或者空串或者其他符合該字段類型的空值。當然如果該字段有明確defaut值,則會填入這個default值。

而oracle,創建表時,如果某字段定義為NOT NULL,並且沒有明確定義default值,則insert時必需在sql語句中寫值,否則報錯。

當然如果該字段有明確的default值,則可以在insert中不填該字段的值。

這樣,項目中的insert就有可能在oracle下跑不通。

 

Mysql的字段默認值有四種:

未定義、自定義的值(包括空串''和'0')CURRENT_TIMESTAMP、0000-00-00 00:00:00

select COLUMN_DEFAULT from information_schema.columns的值,對於未定義的字段,得到NULL;就算這個字段是not null的,也是NULL。

Mysql的默認值(COLUMN_DEFAULT) oracle默認值
NULL 不寫default語句
自定義的值(包括空串''和'0') 寫相應的default語句
CURRENT_TIMESTAMP 暫時不寫default語句
0000-00-00 00:00:00 暫時不寫default語句

 

4、索引問題。

oracle中的索引名不能重復,而mysql可以。

如果重復,報錯:ORA-00955: name is already used by an existing object。

 

5、自增字段問題。

百度“oracle實現自增字段”查了半天,都是基本類似的方法。

(1)sequence + trigger 組合使用。這樣每個表都要有一個 sequence + trigger。有人會認為過多使用觸發器來實現Oracle字段自增,容易造成死鎖或者阻塞。

(2)只用sequence,需要修改系統框架的底層insert的實現,要顯示地調用序列。

兩種方法該用哪一種?

 

 

6、表空間問題。

問了一下同事,說oracle最多支持32G的數據庫。而我們系統經常會超過這個數。

 

 7、oracle的sql中不能用分號結尾,而mysql可以;oracle的sql中不能出現`(按鍵1的左邊),但mysql中經常用它來括住表名。

 

 8、拼接oracle的創建表的sql時,有一個雙引號的問題。

oracle支持的sql語法中,

表名和字段名,可以加雙引號,也可以不加雙引號,但不能加單引號

字段的值如果字符串型,必需加單引號,但不能加雙引號

字段的值如果是數字,可以不加單引號,也可以加單引號,但一定不能加雙引號

比如:$sql = 'select * from zzJkb where "type" = "23"';  //其中type是NUMBER型的。

執行它會報錯:General error: 904 OCIStmtExecute: ORA-00904: "23": 標識符無效 (ext\pdo_oci\oci_statement.c:148)

$sql = 'select * from zzJkb where "type" = 23'; 或者$sql = 'select * from zzJkb where "type" = \'23\'';就正確。

 

對於表名和字段名,加與不加雙引號,oracle理解是有區別的。

$sql = "select * from zzJkb where code = 'abc'"; //這個表名zzJkb,如果不加雙引號,oracle統統識別成大寫,也就是ZZJKB。字段code識別為CODE。

$sql = "select name from zzJkb"; //name 和 zzJkb,統統識別成大寫。如果oracle中只有小寫的zzJkb表名,或者只有小寫的name字段,則匹配不成功。

$sql = 'select "name" from "zzjkb"' ; //name和zzjkb,都識別成雙引號中一模一樣的大小寫形式,不會統一轉成大寫。如果你oracle表中name字段是大寫的或者NaMe,就匹配不成功。

 

/*

oracle中的表名和字段名,都是大小寫敏感的。你可以在里面創建ZZJKB,同時創建ZZjkb或者zzJKB。

 

因為系統里mysql的sql語句,一般不區分大小寫,比如mysql庫里有一張zzjkb全小寫的表名,

$sql = "select * from zzjKB"; //mysql中可以執行成功。

 

如果一個mysql表中的字段名,有大小寫混合的情況,那么select * 出來的結果數組的key是照搬過來,也是大小寫混合。

但是oracle表select *的結果數組中,其key全都是小寫,不管實際庫中的字段是不是大寫,得到的key全都是小寫。

這樣,就不允許一個表的字段名中,出現大小寫混合,要統一成全小寫。否則就會出現程序中得到的key不一致的情況,在mysql和oracle下表現不一致。

可能$onecolumn['Id']在使用mysql時可用,那么在使用oracle時就不可用。

 

而我們程序中拼sql時,對於字段或表名,一般是不加雙引號的(因為一開始支持的是mysql),這樣,在使用oracle時,會被識別成大寫。

結論就是:

1、oracle創建的表名字段名,統統要大寫。(為的是支持系統程序代碼中的sql,因為代碼中的sql對於表名字段名是不加雙引號的,oracle會把這些sql中的表名字段名識別成全大寫)

1.5、拼接oracle的建表sql時,不能出現user這個關鍵字,會報錯,比如

CREATE TABLE beibei_trade (
ttid NUMBER(38) DEFAULT '0' NOT NULL ,
user VARCHAR2(255) DEFAULT '' NULL ,
)
報錯:ORA-00904: : invalid identifier

只能將這種oracle認定的關鍵字,改為雙引號括起,比如"user"或者"USER"。

同樣,在程序的代碼中拼接sql語句,如果user不帶雙引號,oracle也會認為它是關鍵字,不會到表中去匹配user字段的值,搜出的東西永遠是空的。

所以,在程序代碼中,也需要注意有沒有寫user這種字段,需要給它加上雙引號。

 

2、mysql的表名和字段名,統統要小寫。(因為select出的字段,在使用oracle時得到的key全是小寫的,而mysql下得到的key是大小寫區分的)

3、代碼中,所有的sql語句,表名字段名要全部改成小寫。

4、mysql中字段的值,在sql中是不區分大小寫的,比如如果mysql表中實際值為CHU,那么where name = 'Chu' 或者 where name = 'CHU'都可以匹配成功。

這樣,對於使用oracle的系統,匹配就更加嚴格,搜索或者篩選出的結果可能會更少。

5、oracle有可能報錯的地方:

現代碼中,對於表名或字段名,可能會用飄號`將其括起來,oracle不識別會報錯;

現代碼中,sql語句可能出現用雙引號括住字段值(mysql中雙引號或單引號都可以括住字段值),而oracle中字段值一定不能用雙引號,只能用單引號。

現代碼中,sql語句可能會以分號結尾(符合mysql語法),oracle不充許代碼中以分號結尾,所以目前的程序代碼中需要注意,有沒有以分號結束的sql語句;

現代碼中,sql語句中可能出現user這種oracle的關鍵字,需要加上雙引號。比如

select "USER" from beibei_trade3 where USER= 'user' //搜不出東西,因為where后的USER缺少雙引號,oracle不會認為它是字段名。

select "USER" from beibei_trade3 where "USER"= 'user' //可以搜出結果。

 

現代碼中,insert語句,對於mysql,values后面可以不寫全所有字段,插入時mysql會自動插入默認值;但是oracle不行,報ORA-00947: not enough values,除非

你在values前面加上明確的字段名。

比如beibei_trade3表有四個字段:ttid,shop_id,name,lastchanged,

insert into beibei_trade3 values ('', '', 'user')//oracle報錯not enough values,mysql正確。就怕代碼中出現這種情況。

insert into beibei_trade3 (ttid,shop_id,name) values ('', '', 'user') //oracle正確,mysql正確。

 

*/

 

 對當前系統的mysql表做的改動:

1、表ckycdmx中有兩個索引sku_id和sku_dj,它兩的字段一模一樣,oracle不通過。

刪除sku_id這個索引。

2、表YIHAODIAN_ITEMS中,index_tid和tid,兩個索引的字段一模一樣,oracle不通過。

刪除tid這個索引。

 

3、有些表的索引名包含中文,taobao_refunds_trade和taobao_promotion(可能別的表也包含中文索引名稱,但索引名沒超過30個字符,所以沒檢查出)

修改索引名稱去掉中文。

4、四個下划線打頭的表名,去掉下划線。

5、在mysql下,包含seq的表名(104張,除去seq_dj_date,它不是序列表。也就是103張表),實際上是序列表。

 

seq_dj_date這個表,為了不混淆,改名為:dj_date。

在oracle下,這103張表,不需要建。而是用與表名相同的序列代替。比如seq_bonus表,在oracle下實際上沒有該表,但是有SEQ_BONUS這個序列。

在oracle下,也會有DJ_DATE表。

6、region表在mysql下,region_id是主鍵自增字段。要把該字段搞成不要自增。

因為在oracle下,如果某字段自增,會導致插入數據時,該自段不接受傳入的值,而始終使用自增值。region的值是從平台上拉取的,實際上我們希望入庫的值是如下:

 

而在oracle中,入庫的值為:

 

 7、jingdong_trade表,

 這幾個以consignee_info_開頭的字段,有的超過30字符,在oracle中過長,所以去除前面的consignee_info_。

 

8、

 9、taobao_trade表,修改字段:num_iid類型由int(11)  --->  varchar2(50)。該字段是“商品數字編號”,淘寶現在下載下來的這個字段已超過10位。

 

 


 

 

oracle的 一些特性:

oracle創建表時,字段默認是null的,如果你不明確表明NOT NULL還是NULL,則默認是NULL的。  

 oracle在向一個字段寫入空串時,不會寫入空串,而會寫入null,這點跟mysql不同。

不管你是在sql中明確寫明空串'',還是該字段的default值是空串,只要寫入空串,oracle都會自動轉成null寫入表中。

 

 

 

timestamp


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM