Oracle數據庫與PostgreSQL數據庫對比,以及PostgreSQL遇到的各種坑

一.PostgreSQL數據庫簡介:

首先先百度一輪簡介,PostgreSQL 是最先進的開放源碼的數據庫系統, 它提供了多版本並行控制,支持幾乎所有 SQL 構件(包括子查詢,事務和用戶定 義類型和函數), 並且可以獲得非常廣闊範圍的(開發)語言綁定 (包括 C,C++,Java,perl,tcl,和 python)。由於PostgreSQL的開源免費,經歷了從Oracle遷移PG數據庫,遇到了各種坑,閒下來總結下,可能不是很完善,以後工作中遇到問題再來補充。

二.Oracle與PostgreSQL語法對比:

Oracle與PG對比
序號 類型 Oracle PostgreSQL
1 當前時間 SYSDATE 可全部使用current_timestamp替換
2 序列 SEQNAME.NEXTVAL NEXTVAL('SEQNAME')
3 固定值列 SELECT '1' AS COL1 SELECT CAST('1' AS TEXT) AS COL1
4 NVL NVL函數 NVL可以用COALESCE函數替換
5 類型自動轉換 Oracle某些情況下支持類型自動轉換 會出現類型不匹配等錯誤,需要在Java或者sql中進行類型轉換,使類型匹配
6 INSTR函數 instr('str1','str2') strpos('str1','str2')
7 外連接 Oracle可簡寫爲(+) 用LEFT JOIN等語句替換
8 層次查詢

START WITH語句;

CONNECT BY語句;

用WITH RECURSIVE語句;
9 數據庫對象大小寫 不區分大小寫 創建數據庫對象時要小寫,這樣纔不區分SQL的大小寫
10 DECODE等判斷函數 DECODE() 用標準的CASE WHEN THEN ELSE END語句替換
11 同義詞 Oracle支持同義詞 用視圖代替
12 DUAL SELECT 1+1 FROM DUAL SELECT 1+1或者CREATE VIEW dual AS SELECT current_timestamp
13 ROWNUM ROWNUM關鍵字

兩種情況:

1.限制結果集數量,用於翻頁等:SELECT * FROM T LIMIT 5 OFFSET 0;

2.生成行號:使用分析函數ROW_NUMBER() OVER();

14 TO_CHAR TO_CHAR(COL,FMT),格式化字符串可以爲空,用於類型轉換

TO_CHAR(COL1,FMT),不支持FMT爲空,使用類型轉換使用cast()或者string::text的方式,詳細定義見:http://www.postgresql.org/docs/9.4/static/functions-formatting.html

15 TO_NUMBER TO_NUMBER(COL,FMT),格式化字符串可以爲空

TO_NUMBER(COL1,FMT),不支持FMT爲空,使用類型轉換使用cast()或者string::text的方式,詳細定義見:http://www.postgresql.org/docs/9.4/static/functions-formatting.html

16 NULL和'' ORACLE認爲''等同於NULL NULL和''不同
17 NULL和'' LENGTH('')爲NULL LENGTH('')爲0
18 NULL和'' TO_DATE('','YYYYMMDD')爲空 TO_DATE('','YYYYMMDD')爲0001-01-01 BC
19 NULL和'' TO_NUMBER('',1)爲NULL TO_NUMBER('',1),報錯
20 NULL和''

INSERT INTO TEST(VALUE4)VALUES('');

[Result]VALUE4=NULL (注:VALUE4字段爲數值類型)

INSERT INTO TEST(VALUE4)VALUES('');

VALUE4=NULL

21 NULL和''

INSERT INTO TEST(VALUE4)VALUES('');

[Result]VALUE4=NULL (注:VALUE4字段爲字符類型)

INSERT INTO TEST(VALUE4)VALUES('');

VALUE4=''

22 NULL和''

INSERT INTO TEST(VALUE4)VALUES(TO_DATE('','YYYYMMDD'));

[Result]VALUE4=NULL (注:VALUE4字段爲時間類型)

INSERT INTO TEST(VALUE4)VALUES(TO_DATE('','YYYYMMDD'));

[Result]VALUE4=0001-01-01 BC

23 SUBSTR函數 如果從第一個開始取子串,可以從0開始,也可以從1開始,如果不是第一個開始,則從1開始計數,可以爲負值,從字符串結尾計數,用於取最後幾位。 從1開始計數。如果要取最後幾位,可以用RIGHT函數解決。
24 子查詢別名 如果FROM後只有一個子查詢,該子查詢可以沒有別名 必須有別名
25 列(別)名爲關鍵字 Oracle中比如name,type這樣的關鍵字可以直接作爲列的別名,比如:select xx name from t 需要加as,比如select xx as name from t
26 當前登錄用戶 SELECT USER FROM DUAL select current_user
27 修改表字段類型

1.如果字段無數據,可直接修改;

2.如果有數據且新類型和原類型兼容,也可以直接修改;

3.如果不兼容,可通過對原字段改名,然後增加新字段,再通過UPDATE語句對數據進行處理;

1.如果新類型和原類型兼容,可直接修改;

2.如果不兼容,需要使用USING關鍵字然後提供一個類型轉換的表達式;

28

表名

默認爲大寫

默認爲小寫

29

事務處理機制差異

oracle後續語句可以正常操作。

Pg事務中任何操作失敗都會導致後續語句的失敗(包括查詢,dml,lock[ nowait]等),可以開啓ON_ERROR_ROLLBACK臨時解決(影響性能)

30

DDL

Oracle執行 DDL語句如CREATE, DROP, RENAME, or ALTER時,會隱式提交事務;

PG在執行這類語句時,不會提交事務,需顯式提交。

31

字符類型

GBK:漢字字符2個字節,ASCII碼1個字節

UTF8字符集,漢字3個字節,ASCII嗎1個字節

32 查看數據庫中某個表的索引 select * from user_indexes where table_name=upper('表名') select * from pg_statio_all_indexes where relname='表名'
33 查看錶所佔磁盤空間大小 select * from (select owner TABLESPACE_NAME,SUM(BYTES/1024/1024/1024),SEGMENT_NAME FROM dba_segments where segment_type like 'TABLE%' GROUP BY SEGMENT_NAME,TABLESPACE_NAME,owner order by 3 desc) where rownum<=10; 1.PG數據庫查看所有表所佔磁盤空間大小

SELECT SUM(t.SIZE/1024/1024/1024) from ( select table_schema || '.' || table_name as table_full_name,pg_total_relation_size('"'|| table_schema || '"."'||table_name|| '"') as size
        from information_schema.tables order by pg_total_relation_size('"'||table_schema||'"."'||table_name||'"') DESC
)t

2.PG數據庫查看每個表所佔磁盤空間大小
select table_schema || '.' || table_name as table_full_name,pg_total_relation_size('"'|| table_schema || '"."'||table_name|| '"') as size
        from information_schema.tables order by pg_total_relation_size('"'||table_schema||'"."'||table_name||'"') DESC

34 查詢創建索引的語句 select dbms_metadata.get_ddl ('INDEX','PK_TBL_ACC_INFO') from dual; select * from pg_indexes where tablename='表名'

三.Oracle與PostgreSQL差異導致的一些坑:

1.性能測試,通過性能測試發現慢SQL瓶頸,由於oracle和pg有着不同的SQL優化器,所以同一個SQL兩邊可能走不同的執行計劃,進而產生性能差異。

2.postgreSQL 中的||用法與其他數據庫不同:
   select a||b from table1;當a或b其中一個爲null時,該查詢返回null。如果不希望要這個結果,可以使用COALESCE函數:
   select COALESCE(a,'')||COALESCE(b,'') from table1;

3.postgreSQL 一個類型轉換聲明一個從一種數據類型到另外一種數據類型的轉換。
    CAST ( expression AS type )    expression::type
    CAST語法遵循 SQL 標準;::語法是PostgreSQL歷史用法。

4.rownum
PostgresQL 中沒有rownum ,無法 使用where rownum < = X 的方法進行分頁,取而代之的是limit X ,offset Y 方法, 而ORACLE 中不允許使用LIMIT X 的 方法
ORACLE:
SELECT * FROM ( SELECT * FROM (SELECT * FROM SCHEMA.PREFIX_TABLE1 ORDER BY COL1 DESC,COL2 ASC) where ROWNUM <= 50 ORDER BY COL3 ASC,COL4 DESC)
WHERE ROWNUM <= 20 ORDER BY COL5 DESC,COL6 ASC;

postgreSQL:
select * from ( select * from (SELECT * FROM SCHEMA.PREFIX_TABLE1 ORDER BY COL1 DESC,COL2 ASC) selb order by col3 asc,col4 desc limit 50 ) sela
order by col5 desc,col6 asc limit 20;
-- 注意!!limit 必須用於order by 之後
OFFSET說明在開始返回行之前忽略多少行。 OFFSET 0和省略OFFSET子句是一樣的。 如果OFFSET和LIMIT都出現了, 那麼在計算LIMIT個行之前忽略OFFSET行。

如果使用LIMIT,那麼用ORDER BY 子句把結果行約束成一個唯一的順序是一個好主意否則你就會拿到一個不可預料的該查詢的行的子集。 你要的可能是第十到二十行,但以什麼順序的十到二十? 除非你聲明瞭ORDER BY,否則順序是不知道的。

查詢優化器在生成查詢規劃的時候會考慮LIMIT,因此如果你給 LIMIT和OFFSET不同的東西,那麼你很可能收到不同的規劃(產生不同的行順序)。 因此,使用不同的LIMIT/OFFSET值選擇不同的查詢結果的子集將生成不一致的結果, 除非你用ORDER BY強制一個可預料的順序。這可不是臭蟲; 這是一個很自然的結果,因爲 SQL 沒有許諾把查詢的結果按照任何特定的順序發出,除非用了ORDER BY來約束順序。

OFFSET 子句忽略的行仍然需要在服務器內部計算;因此,一個很大的 OFFSET 可能還是不夠有效率的。 

5.空串‘’和null:

在Oracle數據庫中空串和null是等同的,而在PG數據庫中兩者是不同的,這就會引發一個問題,以前Oracle程序中更新一個字段爲空串,但實際查詢時使用is null仍然是可以查到的;而在PG中是查不到的;解決方法有三種:

(1)修改更新代碼,但是工作量很大;

(2)修改後續查詢代碼,在查詢條件中加上 select * from A where (A.aa is null or A.aa =‘’);或者select * from A where (A.aa is  not null and A.aa !=‘’),這樣工作量也不小;

(3)使用觸發器,當更新爲空串時,將其更新爲null;但是使用觸發器可能會有失效;

注意:如果表結構中存在not null 約束,代碼中更新爲空串時,依然可以生效,數據庫中會保存空串,因爲PG數據庫認爲空串和null是不同的,這是最坑的

6.numeric問題:

在Oracle中,numeric類型如果小數點後有0,則會去掉小數點後的0;而PG數據庫會補0;比如numeric(10,3),在Oracle中如果是2.5,則會保存2.5;在PG數據庫中會保存爲2.500;

四.其他常用:

1.查看所有連接的用戶
select * from pg_stat_activity where state='idle';

2.結束連接的進程
--pg_cancel_backend只是取消當前某一個進程的查詢操作,但不能釋放數據庫連接;
--pg_terminate_backend可以在PG的後臺殺死這個進程;
select pg_terminate_backend(2501);--括號中pid

3.使用ASCII查看數據庫中記錄含有回車換行符的數據
 select req_remark from accept_due_pay where req_remark like '%' ||chr(13)||'%' or req_remark like '%' ||chr(10)||'%'
4.去掉數據庫中回車換行符
select replace(replace(req_remark,chr(13),''),chr(10),'') from accept_due_pay where id in ('266363','266364','26365',)

5.PG數據庫修改關鍵字的字段名稱
alter table ent_bank_buss rename "CURRENT_DATE" to current_date1;
alter table ent_bank_buss rename "CURRENT_TIME" to current_time1;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章