轉發自:http://blog.csdn.net/lichangzai/article/details/7955766linux
之前爲開發人員編寫的oracle基礎操做手冊,都基本的oracle操做和SQL語句寫法,適合初學者。sql
因是好久以前寫的,文章中可能會存在不許確的地方,但願指正。shell
ORACLE平常操做手冊數據庫
目錄windows
1. 數據庫的正常啓動步驟...4session
2. 數據庫的正常關閉步驟...4oracle
一、 以DBA用戶登陸數據庫(如system,sys)...5
二、 delete和truncate 、drop的區別...7
Ø Exists和not exists與in和not in的比較...10
Ø 取得當前日期是一個星期中的第幾天,注意星期日是第一天...15
Ø 若是一個表在一個date類型的字段上面創建了索引,如何使用...16
Ø 選擇最有效率的表名順序(只在基於規則的優化器中有效)20
Ø 用EXISTS替代IN和用NOT EXISTS替代NOT IN..24
Ø 避免在索引列上使用IS NULL和IS NOT NULL.28
本文檔約定:
一、 文中的數據庫主要用到了公司cms、pms庫結構
二、 全部SQL都實際的測試經過,放心使用。
三、 若是有再須要瞭解的部分之後能夠再作補充。
l 以DBA的身份登陸數據庫(要在oracle安裝用戶下執行sqlplus)
[oracle@DB1 ~]$sqlplus 「/as sysdba」
l 執行啓動數據庫命令
SQL>startup
ORACLE instance started.
Total System Global Area 285212672 bytes
Fixed Size 1218968 bytes
Variable Size 88082024 bytes
Database Buffers 188743680 bytes
Redo Buffers 7168000 bytes
Database mounted.
Database opened.
[oracle@DB1 ~]$lsnrctl start
[oracle@DB1 ~]$lsnrctl stop
2. 數據庫的正常關閉步驟
l 一樣以DBA的身份登陸數據庫
[oracle@DB1 ~]$sqlplus 「/as sysdba」
l 執行數據庫關閉命令
SQL>shutdown immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.
SHUTDOWN有四個參數:NORMAL、TRANSACTIONAL、IMMEDIATE、ABORT。缺省不帶任何參數時表示是NORMAL。
SHUTDOWN NORMAL:不容許新的鏈接、等待會話結束、等待事務結束、作一個檢查點並關閉數據文件。啓動時不須要實例恢復,這種方法每每不能關閉數據庫或等待很長時間。
SHUTDOWN TRANSACTIONAL:不容許新的鏈接、不等待會話結束、等待事務結束、作一個檢查點並關閉數據文件。啓動時不須要實例恢復。
SHUTDOWN IMMEDIATE:不容許新的鏈接、不等待會話結束、不等待事務結束、作一個檢查點並關閉數據文件。沒有結束的事務是自動rollback的。啓動時不須要實例恢復。最經常使用的方法。
SHUTDOWN ABORT:不容許新的鏈接、不等待會話結束、不等待事務結束、不作檢查點且沒有關閉數據文件。啓動時自動進行實例恢復。通常不推薦採用,只有在數據庫沒法關閉時使用,可能形成數據庫的不一致。
SQL>conn system/oracle@orcl
注:若是在本地服務器登陸@orcl能夠去掉
CREATE USER user_name IDENTIFIED BY user_passwordDefaultTablespace tbs_users;
l user_name爲數據庫用戶的用戶名
l user_password爲數據庫用戶的密碼
l tbs_users爲用戶使用的表空間,默認是users表空間。
例如:
CREATE USER cmsuser IDENTIFIED BY passwordDefaultTablespace users;
alter user user_name quota unlimited on user_tablespace quota unlimited on user_tablespace;
GRANT connect, resource TO cmsuser;
l Connect用戶能登陸數據庫的權限
l Resource用戶能建立一些數據庫對像的權限,表、視圖,存儲過程,通常是授予開發人員的
DropUser cmsuser Cascade;
l 使用cascade參數能夠刪除該用戶的所有objects
l INTEGER存儲整數,整數不包括浮點數;它是一個整數數字,如:一、十、15
l NUMBER,是以十進制格式進行存儲的,它便於存儲,可是在計算上,系統會自動的將它轉換成爲二進制進行運算的。它的定義方式是NUMBER(P,S),P是精度,最大38位,S是刻度範圍,可在-84...127間取值。例如:NUMBER(5,2)能夠用來存儲表示-999.99...999.99間的數值。P、S能夠在定義是省略,例如:NUMBER(5)、NUMBER等;
l CHAR,描述定長的字符串,若是實際值不夠定義的長度,系統將以空格填充。它的聲明方式以下CHAR(L),L爲字符串長度,缺省爲1,做爲變量最大32767個字符,做爲數據存儲在ORACLE8中最大爲2000。
l VARCHAR2(VARCHAR),描述變長字符串。它的聲明方式以下VARCHAR2(L),L爲字符串長度,沒有缺省值,做爲變量最大32767個字節,做爲數據存儲在ORACLE8中最大爲4000。在多字節語言環境中,實際存儲的字符個數可能小於L值,例如:當語言環境爲中文(SIMPLIFIED CHINESE_CHINA.ZHS16GBK)時,一個VARCHAR2(200)的數據列能夠保存200個英文字符或者100個漢字字符。
l NCHAR、NVARCHAR2,國家字符集,與環境變量NLS指定的語言集密切相關,使用方法和CHAR、VARCHAR2相同。不過最大參數爲NCHAR(2000)、NVARCHAR2(2000)
l DATE惟一的一種日期類型--,用來存儲時間信息,站用7個字節(從世紀到秒)
l LOB(oracle8之前叫long)變量主要是用來存儲大量數據的數據庫字段,最大能夠存儲4G字節的內容,CLOB:存儲單字節字符數據(如英文)NCLOB:用來存儲定寬多字節字符數據(如漢字),BLOB:用來存儲無結構的二進制數據(word、pdf文檔)。
rowid是Oracle數據庫中的每一行都有一個惟一的行標識符,稱爲rowid,它是一個18位數字,以64爲基數,該徝包含了該行在oracle數據庫中的物理位置,查詢rowid以下:
SQL> Select rowid,id From infobase Where Rownum < 5;
ROWID ID
------------------ ---------
AAAYKRAAEAAGGpcAAI 1000000
AAAYKRAAEAAGGpcAAJ 1000001
AAAYKRAAEAAGGpcAAK 1000002
AAAYKRAAEAAGGpcAAL 1000003
Rowid應用實例:
DeleteFrom Infobase a
Where Rowid < (Select Max(Rowid)From Infobase Where Id = a.Id);
使用下面的語句可使表處於可編輯狀態,可手工添加、刪除、更改記錄。而後分別點擊pl/sql Dev的按
Select t.Rowid,t.*From infobase t;
rownum 被稱爲「僞數列」,是事實上不存在一個數列,它的特色是按照順序標記,並且是逐次遞加,換句話說只有存在rownum=1的記錄,纔有可能有rownum=2的記錄。查詢以下:
SQL> Select Rownum,id From infobase Where Rownum < 5;
ROWNUM ID
---------- ---------
1 1000000
2 1000001
3 1000002
4 1000003
rownum應用實例:
若是要刪除的數據量很大,一次刪除可能須要佔用系統大量的內存,給數據庫帶來很大的壓力,能夠進行分步批量刪除並提交,避免這種狀況
createor replace procedure del_data
as --建立過程並執行
begin
for i in 1..1000loop
delete from cmsuser_zbxy.infobase Where posterid='Servlet提交'and rownum < 100;
commit;
end loop;
End del_data;
Select *
From (Select * From InfobaseOrder By Originaltime Desc)
Where Rownum <= 10;
TRUNCATE TABLE 在功能上與不帶WHERE子句的DELETE語句相同:兩者均刪除表中的所有行。但 TRUNCATE TABLE比 DELETE速度快,且使用的系統和事務日誌資源少。
Drop 則是刪除整個表,與TRUNCATE操做類型相同,都是DDL操做(數據定義語言)
DeleteFrom infobase Id = 1;
Commit;
--或
Delete infobase Where Id = 1;
Commit;
TruncateTable infobase;
DropTable infobase;
根據鏈接中使用操做符的不一樣,鏈接條件能夠分爲兩類:
l 等鏈接:在鏈接中使用等於操做符(=)
l 不等鏈接:在鏈接中使用除等號以外的操做符,如:<、>、between等
除鏈接條件區分以外,鏈接自己也有3種不一樣的類型:
l 內鏈接:只有當鏈接中的列包含知足鏈接條件的值時纔會返回一行。這就是說,若是某一行的鏈接條件中的一列是空值,那麼這行就不返回。
l 外鏈接:即便鏈接條件中的一列包含空值也會返回一行。
l 自鏈接:返回鏈接的同一個表中的行。
Select e.first_name,e.title,e.salary,sg.salary_grade_id
From employees e,salary_grades sg
Where e.salary Between sg.low_salary And sg.high_salary;
--employees員工表,salary_grades工資等級表
Select a.Id, b.Name, a.Title, a.Content
From Infobase a
Join Class b On a.Classid = '(' || b.Id || ')';
--或
Select a.Id, b.Name, a.Title, a.Content
From Infobase a Class b
Where a.Classid = '(' || b.Id ||')';
Update Infobase a
Set a.Title = (Select Title From Infobase_TempWhere Id = a.Id);
Commit;
Delete From Infobase a
Where Exists ( Select 1 From Class bWhere a.classid = b.id);
Commit;
Select a.*
From Infobase a
Left Join Attachment b On a.Id = b.Infoid
Where b.Infoid Is Null;
--這是典型兩表相減查詢,也可用not in,可是種寫法效率會高些
--這是一個左外鏈接例子,右外鏈接跟左外鏈接同樣,只是表的位置不一樣
Select w.Last_Name ||' works for ' || m.Last_Name
From Employees m, Employees w
Where w.Employee_Id = m.Manager_Id;
下面的語法也能夠看作成一個隱含的自鏈接查詢,它是一個字列和父列的遞歸查詢
Select *
From Class
Start With Parentid = 0001
Connect By Prior Id = Parentid
--id,parentid那麼經過表示每一條記錄的parent是誰,就能夠造成一個樹狀結構
--Parentid = 0001指定樹的根從哪一個節點開始
子查詢有兩種基本類型:
l 單行子查詢:不向外部的SQL返回結果,或者只返回一行。
l 多行子查詢:向外部的SQL返回一行或多行。
另外子查詢還有三種子類型:
l 多列子查詢:向外部的SQL語句返回多列。
l 關聯子查詢:引用外的SQL語句中的一錢或多列。
l 嵌套子查詢:位於另一個子查詢中。子查詢最多能夠嵌套255層。
Select *
From Infobase
Where Contentsize > (Select Avg(Contentsize) From Infobase);
檢索那些平均價格低於同類產品平均價格最大值的產品的product_type_id和平均價格:
Select Product_Type_Id,Avg(Price)
From Products
Group By Product_Type_Id
Having Avg(Price) < (Select Max(Avg(Price))
From Products
Group By Product_Type_Id);
就外部查詢的from子句而言,子查詢的輸出僅僅是另一個數據源。
檢索Productid大於100的產品
Select Productid
From (Select Productid From ProductWhere Productid < 100);
在外部查詢中從products表中檢索product_id和price列,在子查詢中檢索一種產品已經被購買的次數:
Select a.Product_Id, a.Price, b.Product_Count
From Products a,
(Select Product_Id, Count(Product_Id) Product_Count
From Purchases
Group By Product_Id) b
Where a.Product_Id = b.Product_Id;
(1)、單行查詢最多返回一行
SQL> Select Productid, Productname
2 From Product
3 Where Productid =
4 (Select Productid From Product Where Productname Like '恆泰%');
Select Productid, Productname
ORA-01427:單行子查詢返回多於一個行
(2)、子查詢不能包含order by子句,必須在外查詢中進行任何排序
檢索信息表裏符合classid條件的記錄:
Select *
From Infobase
Where Classid In
(Select '(' ||Id || ')'From Class Where Name Like '營業部%')
檢查是否有任何員工的工資低於salary_grades表中任何一級的最低工資:
Select e.Employee_Id, e.Last_Name
From Employees e
Where e.Salary < Any (Select Sg.Low_SalaryFrom Salary_Grades Sg);
檢查是否有任何員工的工資高於salary_grades表中全部級別的最高工資:
Select e.Employee_Id, e.Last_Name
From Employees e
Where e.Salary > All (Select sg.high_salaryFrom Salary_Grades Sg);
Select *
From Products
Where (Product_Type_Id, Price) In
(Select Product_Type_Id, Min(Price)
From Products
Group By Product_Type_Id);
--上面的寫法也如同下面的寫法,返回結果同樣
Select *
From Products a
Where Price = (Select Min(Price)
From Products
Where Product_Type_Id = a.Product_Type_Id);
--注意:這個例子是平常的開發很典型的例子,會常常用到,必定要學會應用
檢索那些負責管理其它員工的員工記錄:
Select Employee_Id, Last_Name
From Employees
Outer Where Exists
(Select Employee_Id
From Employees Inner
Inner Where Inner.Manager_Id = Outer.Employee_Id);
檢索從未購買過的產品
Select Product_Id,Name
From Products a
Where Not Exists (Select 1 From Purchases Where Product_Id = a.Product_Id)
-- 子句的1是個虛擬列,沒有意義,改爲其它值也能夠
Ø Exists和not exists與in和not in的比較
Exists與in不一樣,Exists只檢查行的存在性,而in則要檢查實際值的存在性。
一般來說,Exists的性能要比in要高一些,所以應該儘量地使用Exists,而不用in。
在編寫使用Not Exists和Not in的查詢時必需要謹慎。當一個值列表包含一個空值時,Not Exists就返回true,而Not in 則返回false。考慮下面這個例子:本例使用了Not Exists,檢索那些在products表中沒有任何產品的產品類型:
Select Product_Type_Id,Name
From Product_Types a
Where Not Exists
(Select 1From Products Where Product_Type_Id = a.Product_Type_Id);
PRODUCT_TYPE_ID NAME
---------------------------------- ----------
5 Magazine
注意上面這個例子返回了一行記錄。下面這個例子使用Not in重寫了上面這個例子,而此時沒有返回任何行:
Select Product_Type_Id,Name
From Product_Types a
Where Product_Type_Id Not In (Select Product_Type_IdFrom Products);
PRODUCT_TYPE_ID NAME
---------------------------------- ----------
這因此沒有返回行,就是由於子查詢返回Product_Type_Id值的列表,其中包含一個空值。而產品#12的Product_Type_Id是空值。所以外部查詢中的Not in操做符返回false,所以沒有任何行。這個問題可使用Nvl()函數將空值轉換成一個值解決。
下面的例子中,Nvl()函數將空值的Product_Type_Id轉換成0:
Select Product_Type_Id,Name
From Product_Types a
Where Product_Type_Id Not In (Select nvl(Product_Type_Id,0)From Products);
PRODUCT_TYPE_ID NAME
---------------------------------- ----------
5 Magazine
此次返回了咱們要獲得的那行記錄。
在子查詢內部能夠嵌套其它子查詢,嵌套層次最多爲255。在編寫時應該儘可能少使用嵌套子查詢技術,由於使用錶鏈接時,查詢性能會更高。下面的例子包含了一個嵌套子查詢,子查詢包含了另一個子查詢,而它本身又被包含在一個外部查詢中:
Select Product_Type_Id,Avg(Price)
From Products
Group By Product_Type_Id
Having Avg(Price) < (Select Max(Avg(Price))
From Products
Where Product_Type_Id In
(Select Product_Id
From Purchases
Where Quantity >= 1)
Group By Product_Type_Id);
這個查詢包含了3個查詢:一個嵌套子查詢、一個子查詢和一個外部查詢。能夠由裏到外本身逐步分析,獲得運行結果。
集合操做符能夠將兩個或多個查詢返回的行組合起來,當使用集合操做符的時候,必須牢記下列的限制條件:全部查詢所返回的列數以及列的類型必須匹配,列名能夠不一樣。
集合操做符主要有:
l Union all 返回各個查詢檢索出的全部行,包括重複的行。
l Union 返回各個查詢檢索出的全部行,不包括重複的行。
l Intersect 返回兩個查詢共有行。
l Minus 返回第二個查詢檢索出的行從第一個查詢檢索出的行中減去以後剩餘的記錄。
Union all 返回各個查詢檢索出的全部行,包括重複的行
SelectId,classid From infobase Where Rownum <5
Union All
Select Id,classid From infobase_temp;
ID CLASSID
---------- --------------------------------------------------------------------------------
1000000 (000100010002)
1000001 (000200020003000100010002)
1000002 (000100010003)
1000005 (00010001000400030007)
1000000 (000100010002)
1000001 (000200020003000100010002)
可使用order by子句根據兩個查詢中的列的位置對列進行排序。
SelectId,classid From infobase Where Rownum <5
Union All
Select Id,classid From infobase_temp
Order By 1;
ID CLASSID
---------- --------------------------------------------------------------------------------
1000000 (000100010002)
1000000 (000100010002)
1000001 (000200020003000100010002)
1000001 (000200020003000100010002)
1000002 (000100010003)
1000005 (00010001000400030007)
返回各個查詢檢索出的全部行,不包括重複的行。由於Union查詢時要有排重操做,因此Union all要比Union操做效率要高一些。
SelectId,classid From infobase Where Rownum <5
Union
Select Id,classid From infobase_temp;
ID CLASSID
---------- --------------------------------------------------------------------------------
1000000 (000100010002)
1000001 (000200020003000100010002)
1000002 (000100010003)
1000005 (00010001000400030007)
Intersect 返回兩個查詢共有行
只檢索出那些infobase與infobase_temp共有的行
SelectId,classid From infobase Where Rownum <5
intersect
Select Id,classid From infobase_temp;
ID CLASSID
---------- --------------------------------------------------------------------------------
1000000 (000100010002)
1000001 (000200020003000100010002)
Minus 返回第二個查詢檢索出的行從第一個查詢檢索出的行中減去以後剩餘的記錄.
下例是從infobase返回的行中減去從infobase_temp中返回的行,而後返回剩餘的行:
SelectId,classid From infobase Where Rownum <5
Minus
Select Id,classid From infobase_temp;
ID CLASSID
---------- --------------------------------------------------------------------------------
1000002 (000100010003)
1000005 (00010001000400030007)
Decode(value,search_value,result,default_value)對value與search_value進行比較,若是兩個值相等,Decode()返回result,不然返回default_value。Decode()容許if-then-else類型的邏輯處理,而不須要使用pl/sql。
下面是個簡單的例子:
SQL> Select decode(1,1,2,3) From dual;
DECODE(1,1,2,3)
---------------
2
由於對1與1進行比較,因爲二者相等,因此返回2(不然返回3)
Decode一般在寫SQL時與dual表結合給變量賦值。
下面這個例子對more_products中的available列進行比較。若是available等於Y,返回字符串Product is available,不然返回字符串Product is not available:
Select Prd_Id,
Available,
Decode(Available,
'Y',
'Product is available',
'Product is not available')
From More_Products;
PRD_ID AVAILABLE DECODE(AVAILABLE,'Y','PRODUCTI
--------------------------------------- --------- ------------------------------
1 Y Product is available
2 Y Product is available
3 N Product is not available
4 N Product is not available
5 Y Product is available
能夠向Decode()傳遞多個搜索和結果參數,以下例:
Select Product_Id,
Product_Type_Id,
Decode(Product_Type_Id, 1,'Book', 2, 'Video',3, 'Dvd','CD')
From Products;
若是Product_Type_Id=1,返回Book
若是Product_Type_Id=2,返回Video
若是Product_Type_Id=3,返回Dvd
若是Product_Type_Id等於其它值,返回CD
case容許if-then-else類型的邏輯處理,而不須要使用pl/sql。Case的工做方式與Decode()相似,一般咱們在有較少的判斷時使用decode,由於條件多話會看着很混亂;因此儘可能使用case,它與ANSI兼容。
有兩種類型的case表達式:
l 簡單case表達式,使用表達式肯定返回值。
l 搜索case表達式,使用條件肯定返回值。
使用簡單表達式例子:
Select Product_Id,
Product_Type_Id,
Case Product_Type_Id
When 1Then 'Book'
When 2Then 'Video'
When 3Then 'Dvd'
Else 'CD'
End
From Products;
PRODUCT_ID PRODUCT_TYPE_ID CASEPRODUCT_TYPE_IDWHEN1THEN'B
--------- -------------------------------- ------------------------------
1 1 Book
2 1 Book
3 2 Video
4 2 Video
5 2 Video
6 2 Video
7 3 Dvd
8 3 Dvd
9 4 CD
使用搜索case表達式
Select Product_Id,
Product_Type_Id,
Case
When Product_Type_Id = 1Then 'Book'
When Product_Type_Id = 2 Then 'Video'
When Product_Type_Id = 3 Then 'Dvd'
Else 'CD'
End
From Products;
返回結果中上面是同樣的
l MONTHS_BETWEEN兩日期相差多少月
l ADD_MONTHS 加月份到日期
l NEXT_DAY 指定日期的下一天
l LAST_DAY 一個月中的最後一天
l ROUND Round日期
l TRUNC Truncate日期
l TO_CHAR(x[,format])函數用於將時間值轉換爲字符串,該函數還能夠提供一個可選的參數format來講明x的格式。如:MONTH DDD,YYYY
l TO_DATE(x[,format])將字符串x轉換成date類型。
下面是幾個關於日期方面的SQL實例
SQL> select to_char(sysdate,'YYYYMMDD W HH24:MI:SS') from dual;
TO_CHAR(SYSDATE,'YYYYMMDDWHH24
------------------------------
20090202 1 18:00:43
SQL> select to_char(sysdate,'W') from dual;
TO_CHAR(SYSDATE,'W')
--------------------
1
SQL> select sysdate,to_char(sysdate,'D') from dual;
SYSDATE TO_CHAR(SYSDATE,'D')
----------- --------------------
2009-2-2 18 2
select to_char(sysdate,'yyyy') from dual; --年
select to_char(sysdate,'Q' from dual; --季
select to_char(sysdate,'mm') from dual; --月
select to_char(sysdate,'dd') from dual; --日
ddd年中的第幾天
WW年中的第幾個星期
W該月中第幾個星期
D週中的星期幾
hh小時(12)
hh24小時(24)
Mi分
ss秒
SQL> select to_char(sysdate,'day') from dual;
TO_CHAR(SYSDATE,'DAY')
----------------------
星期四
Ø 若是一個表在一個date類型的字段上面創建了索引,如何使用
alter session set NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'
select sysdate from dual;
SYSDATE
-----------
2009-2-2 18
select trunc(sysdate) from dual;
TRUNC(SYSDATE)
--------------
2009-2-2
select trunc(sysdate) + 0.99999 from dual;
TRUNC(SYSDATE)+0.99999
----------------------
2009-2-2 23:59:59
select trunc(sysdate) + 1/24 from dual;
TRUNC(SYSDATE)+1/24
-------------------
2009-2-2 1:00:00
select trunc(sysdate) + 7/24 from dual;
TRUNC(SYSDATE)+7/24
-------------------
2009-2-2 7:00:00
select trunc(sysdate+1) from dual;
TRUNC(SYSDATE+1)
----------------
2009-2-3
select trunc(sysdate,'mm') from dual;
TRUNC(SYSDATE,'MM')
-------------------
2009-2-1
select trunc(add_months(sysdate,1),'mm') from dual;
TRUNC(ADD_MONTHS(SYSDATE,1),'M
------------------------------
2009-3-1
SQL> select last_day(sysdate) from dual;
LAST_DAY(SYSDATE)
-----------------
2009-2-28 18:11:3
SQL> select last_day(trunc(sysdate)) from dual;
LAST_DAY(TRUNC(SYSDATE))
------------------------
2009-2-28
SQL> select trunc(last_day(sysdate)) from dual;
TRUNC(LAST_DAY(SYSDATE))
------------------------
2009-2-28
SQL> select trunc(add_months(sysdate,1),'mm') - 1 from dual;
TRUNC(ADD_MONTHS(SYSDATE,1),'M
------------------------------
2009-2-28
Select Trunc(Sysdate, 'yyyy') + Rn - 1 Date0
From (Select Rownum Rn From All_Objects Where Rownum < 366);
DATE0
-----------
2009-1-1
2009-1-2
2009-1-3
……
今天是今年的第N天
SQL> SELECT TO_CHAR(SYSDATE,'DDD') FROM DUAL;
TO_CHAR(SYSDATE,'DDD')
----------------------
033
SQL> select add_months(sysdate,24) from dual;
ADD_MONTHS(SYSDATE,24)
----------------------
2011-2-2 18:15:56
SQL> select decode(to_char(last_day(trunc(sysdate,'y')+31),'dd'),'29','閏年','平年') from dual;
DECODE(TO_CHAR(LAST_DAY(TRUNC(
------------------------------
平年
SQL> select decode(to_char(last_day(trunc(add_months(sysdate,24),'y')+31),'dd'),'29','閏年','平年') from dual;
DECODE(TO_CHAR(LAST_DAY(TRUNC(
------------------------------
平年
SQL> select ceil(to_number(to_char(sysdate,'mm'))/3) from dual;
CEIL(TO_NUMBER(TO_CHAR(SYSDATE
------------------------------
1
SQL> select to_char(sysdate, 'Q') from dual;
TO_CHAR(SYSDATE,'Q')
--------------------
1
ORACLE 採用兩種訪問表中記錄的方式:
l 全表掃描
全表掃描就是順序地訪問表中每條記錄. ORACLE採用一次讀入多個數據塊(database block)的方式優化全表掃描.
l 經過ROWID訪問表
你能夠採用基於ROWID的訪問方式狀況,提升訪問表的效率, , ROWID包含了表中記錄的物理位置信息..ORACLE採用索引(INDEX)實現了數據和存放數據的物理位置(ROWID)之間的聯繫.一般索引提供了快速訪問ROWID的方法,所以那些基於索引列的查詢就能夠獲得性能上的提升.
索引是表的一個概念部分,用來提升檢索數據的效率.經過索引查詢數據比全表掃描要快.當ORACLE找出執行查詢和Update語句的最佳路徑時, ORACLE優化器將使用索引.一樣在聯結多個表時使用索引也能夠提升效率. 另外一個使用索引的好處是,它提供了主鍵(primary key)的惟一性驗證.除了那些LONG或LONG RAW、LOB數據類型,你能夠索引幾乎全部的列. 一般,在大型表中使用索引特別有效. 固然,你也會發現,在掃描小表時,使用索引一樣能提升效率.
雖然使用索引能獲得查詢效率的提升,可是咱們也必須注意到它的代價.索引須要空間來
存儲,也須要按期維護,每當有記錄在表中增減或索引列被修改時, 索引自己也會被修改.這意味着每條記錄的INSERT , DELETE , UPDATE將爲此多付出4 , 5次的磁盤I/O . 由於索引須要額外的存儲空間和處理,那些沒必要要的索引反而會使查詢反應時間變慢。
大多數狀況下,優化器經過WHERE子句訪問INDEX.
按期的重構索引是有必要的.
ALTER INDEX <INDEXNAME> REBUILD <TABLESPACENAME>
CreateIndex infobase_title On infobase(title);
--建立惟一索引
Createunique Index infobase_key On infobase (Id);
--建立全文索引
CREATE INDEX infobase_content ON infobase(content)INDEXTYPE IS CTXSYS.CONTEXT;
--在全文索引進行檢索
SELECT * FROM infobase WHERE CONTAINS (content,'first') > 0;
--建立同步全文索引過程
create or replace procedure sync_content
is
begin
execute immediate
'alter index infobase_content rebuild online' ||
' parameters ( ''sync'' )' ;
execute immediate
'alter index infobase_content rebuild online' ||
' parameters ( ''optimize full maxtime unlimited'' )' ;
end sync_content;
/
--建立做業執行同步過程
variable n number;
begin
dbms_job.submit(:n,'sync_content;',sysdate,
'sysdate+1/48');
commit;
end;
/
AlterTable infobase
Add Constraints infobase_key Primary Key(Id);
--表上建立主建至關於在列上的建了一個惟一的索引
在WHERE子句中,若是索引列所對應的值的第一個字符由通配符(WILDCARD)開始,索引將不被採用.如:like ‘%標題’。
這一點必定要注意。由於在咱們開發的過程當中常常遇到這樣的問題,like ‘%標題%’會掃描全表,會給數據庫的性能帶來很大的壓力。要儘量避免這種寫法,若是有必要能夠用全文索引代替。以下面的例子:
selectcount(*) from infobase
where classid in ('(0001000300030001)','(0001000300030002)')
and (category like '%600755%' or category like'%600976%');
--可用全文索引代替
select count(*) from infobase
where classid in ('(0001000300030001)','(0001000300030002)')
and (CONTAINS (category, '600755') > 0or CONTAINS (category, '600976') > 0 );
但like ‘標題%’這種寫法會使用索引
ORACLE的解析器按照從右到左的順序處理FROM子句中的表名,所以FROM子句中寫在最後的表(基礎表 driving table)將被最早處理. 在FROM子句中包含多個表的狀況下,你必須選擇記錄條數最少的表做爲基礎表.當ORACLE處理多個表時,會運用排序及合併的方式鏈接它們.首先,掃描第一個表(FROM子句中最後的那個表)並對記錄進行派序,而後掃描第二個表(FROM子句中最後第二個表),最後將全部從第二個表中檢索出的記錄與第一個表中合適記錄進行合併.
例如:
表 TAB1 16,384條記錄
表 TAB2 1條記錄
選擇TAB2做爲基礎表 (最好的方法)
select count(*) from tab1,tab2
執行時間0.96秒
選擇TAB2做爲基礎表 (不佳的方法)
select count(*) from tab2,tab1
執行時間26.09秒
若是有3個以上的錶鏈接查詢,那就須要選擇交叉表(intersection table)做爲基礎表,交叉表是指那個被其餘表所引用的表.
例如:
EMP表描述了LOCATION表和CATEGORY表的交集.
SELECT *
FROM LOCATION L ,
CATEGORY C,
EMP E
WHERE E.EMP_NO BETWEEN 1000 AND 2000
AND E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
將比下列SQL更有效率
SELECT *
FROM EMP E ,
LOCATION L ,
CATEGORY C
WHERE E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
AND E.EMP_NO BETWEEN 1000 AND 2000
ORACLE採用自下而上的順序解析WHERE子句,根據這個原理,表之間的鏈接必須寫在其餘WHERE條件以前,那些能夠過濾掉最大數量記錄的條件必須寫在WHERE子句的末尾.
例如:
第二個SQL要比第一個SQL查詢效率高:
SELECT *
FROM EMP E
WHERE SAL > 50000
AND JOB = ‘MANAGER'
AND 25 < (SELECT COUNT(*) FROM EMP
WHERE MGR=E.EMPNO);
SELECT *
FROM EMP E
WHERE 25 < (SELECT COUNT(*) FROM EMP
WHERE MGR=E.EMPNO)
AND SAL > 50000
AND JOB = ‘MANAGER';
當你想在SELECT子句中列出全部的COLUMN時,使用動態SQL列引用‘*'是一個方便的方法.不幸的是,這是一個很是低效的方法.實際上,ORACLE在解析的過程當中,會將'*' 依次轉換成全部的列名,這個工做是經過查詢數據字典完成的, 這意味着將耗費更多的時間.
當執行每條SQL語句時, ORACLE在內部執行了許多工做:解析SQL語句,估算索引的利用率, 綁定變量 ,讀數據塊等等. 因而可知,減小訪問數據庫的次數 , 就能實際上減小ORACLE的工做量.
例如,
如下有三種方法能夠檢索出僱員號等於0342或0291的職員.
方法1 (最低效)
SELECT EMP_NAME , SALARY , GRADE
FROM EMP
WHERE EMP_NO = 342;
SELECT EMP_NAME , SALARY , GRADE
FROM EMP
WHERE EMP_NO = 291;
方法2 (次低效)
DECLARE
CURSOR C1 (E_NO NUMBER) IS
SELECT EMP_NAME,SALARY,GRADE
FROM EMP
WHERE EMP_NO = E_NO;
BEGIN
OPEN C1(342);
FETCH C1 INTO …,..,.. ;
…..
OPEN C1(291);
FETCH C1 INTO …,..,.. ;
CLOSE C1;
END;
方法3 (高效)
SELECT A.EMP_NAME , A.SALARY , A.GRADE,
B.EMP_NAME , B.SALARY , B.GRADE
FROM EMP A,EMP B
WHERE A.EMP_NO = 342
AND B.EMP_NO = 291;
只要有可能,在程序中儘可能多使用COMMIT,這樣程序的性能獲得提升,需求也會由於COMMIT所釋放的資源而減小:
COMMIT所釋放的資源:
a. 回滾段上用於恢復數據的信息.
b. 被程序語句得到的鎖
c. redo log buffer 中的空間
d. ORACLE爲管理上述3種資源中的內部花費
注意: 在使用COMMIT時必需要注意到事務的完整性,現實中效率和事務完整性每每是魚和熊掌不可得兼
在含有子查詢的SQL語句中,要特別注意減小對錶的查詢.
例如:
低效
Select Tab_Name
From Tables
Where Tab_Name = (Select Tab_Name From Tab_ColumnsWhere Version = 604)
And db_Ver = (Select Db_VerFrom Tab_Columns Where Version = 604);
高效
Select Tab_Name
From Tables
Where (Tab_Name, Db_Ver) = (Select Tab_Name, Db_Ver From Tab_Columns
Where Version = 604);
Update 多個Column例子:
低效:
Update Emp
Set Emp_Cat = (Select Max(Category)From Emp_Categories),
Sal_Range = (Select Max(Sal_Range) From Emp_Categories)
Where Emp_Dept = 0020;
高效:
Update Emp
Set (Emp_Cat, Sal_Range) = (Select Max(Category),Max(Sal_Range)
From Emp_Categories)
Where Emp_Dept = 0020;
下面是一個複雜的多表關聯查詢:
Select h.Empno, e.Ename, h.Hist_Type, t.Type_Desc,Count(*)
From History_Type t, Emp e, Emp_History h
Where h.Empno = e.Empno
And h.Hist_Type = t.Hist_Type
Group By h.Empno, e.Ename, h.Hist_Type, t.Type_Desc;
經過調用下面的函數能夠提升效率:
Function Lookup_Hist_Type(TypIn Number) Return Varchar2 As
Tdesc Varchar2(30);
Cursor C1 Is
Select Type_Desc From History_Type Where Hist_Type = Typ;
Begin
Open C1;
Fetch C1
Into Tdesc;
Close C1;
Return(Nvl(Tdesc, '?'));
End;
Function Lookup_Emp(Emp In Number) Return Varchar2 As
Ename Varchar2(30);
Cursor C1 Is
Select Ename From Emp Where Empno = Emp;
Begin
Open C1;
Fetch C1
Into Ename;
Close C1;
Return(Nvl(Ename, '?'));
End;
--可用下在SQL來調用上面的兩個函數
Select h.Empno,
Lookup_Emp(h.Empno),
h.Hist_Type,
Lookup_Hist_Type(h.Hist_Type),
Count(*)
From Emp_History h
Group By h.Empno, h.Hist_Type;
注:有時一個複雜的查詢能夠用一個複雜的SQL能夠完成,卻不知複雜的SQL每每犧牲了執行效率. 可以掌握上面的運用函數解決問題的方法在實際工做中是很是有意義的。
當在SQL語句中鏈接多個表時,請使用表的別名並把別名前綴於每一個Column上.這樣一來,就能夠減小解析的時間並減小那些由Column歧義引發的語法錯誤.
Ø 用EXISTS替代IN和用NOT EXISTS替代NOT IN
在前面的章節已經介紹過,不在描述。
一般來講 , 採用錶鏈接的方式比EXISTS更有效率
Select Ename
From Emp e
Where Exists (Select 'X'
From Dept
Where Dept_No = e.Dept_No
And Dept_Cat = 'A');
更高效
Select Ename
From Dept d, Emp e
Where e.Dept_No = d.Dept_No
And Dept_Cat = 'A';
當提交一個包含一對多表信息(好比部門表和僱員表)的查詢時,避免在SELECT子句中使用DISTINCT.通常能夠考慮用EXIST替換
例如:
低效:
SelectDistinct Dept_No, Dept_Name
From Dept d, Emp e
Where d.Dept_No = e.Dept_No;
高效:
Select Dept_No, Dept_Name
From Dept d
Where Exists (Select 'X' From Emp e Where e.Dept_No = d.Dept_No);
EXISTS 使查詢更爲迅速,由於RDBMS核心模塊將在子查詢的條件一旦知足後,馬上返回結
果.
當WHERE子句中有索引列, ORACLE不能合併它們,ORACLE將用範圍比較.
舉例:
DEPTNO上有一個非惟一性索引,EMP_CAT也有一個非惟一性索引.
Select Ename
From Emp
Where Deptno > 20
And Emp_Cat = 'A';
這裏只有EMP_CAT索引被用到,而後全部的記錄將逐條與DEPTNO條件進行比較.執行路徑以下:
TABLEACCESS BY ROWID ON EMP
INDEX RANGE SCAN ON CAT_IDX
當ORACLE沒法判斷索引的等級高低差異,優化器將只使用一個索引,它就是在WHERE子句中被列在最前面的.
舉例:
DEPTNO上有一個非惟一性索引,EMP_CAT也有一個非惟一性索引.
Select Ename
From Emp
Where Deptno > 20
And Emp_Cat > 'A';
這裏, ORACLE只用到了DEPT_NO索引.執行路徑以下:
TABLEACCESS BY ROWID ON EMP
INDEX RANGE SCAN ON DEPT_IDX
咱們來試一下如下這種狀況:
SQL> select index_name, uniqueness from user_indexes where table_name = 'EMP';
INDEX_NAME UNIQUENES
------------------------------ ---------
EMPNO UNIQUE
EMPTYPE NONUNIQUE
SQL> select * from emp where empno >= 2 and emp_type = 'A' ;
no rows selected
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
2 1 INDEX (RANGE SCAN) OF 'EMPTYPE' (NON-UNIQUE)
雖然EMPNO是惟一性索引,可是因爲它所作的是範圍比較,等級要比非惟一性索引的等式比較低!
若是兩個或以上索引具備相同的等級,你能夠強制命令ORACLE優化器使用其中的一個(經過它,檢索出的記錄數量少)
舉例:
Select Ename
From Emp
Where Empno = 7935
And Deptno + 0 =10/*DEPTNO上的索引將失效*/
And Emp_Type || '' ='A'/*EMP_TYPE上的索引將失效*/
這是一種至關直接的提升查詢效率的辦法.可是你必須謹慎考慮這種策略,通常來講,只有在你但願單獨優化幾個SQL時才能採用它.
這裏有一個例子關於什麼時候採用這種策略:
假設在EMP表的EMP_TYPE列上有一個非惟一性的索引而EMP_CLASS上沒有索引.
Select Ename
From Emp
Where Emp_Type = 'A'
And Emp_Class = 'X';
優化器會注意到EMP_TYPE上的索引並使用它.這是目前惟一的選擇. 若是,一段時間之後,另外一個非惟一性創建在EMP_CLASS上,優化器必須對兩個索引進行選擇,在一般狀況下,優化器將使用兩個索引並在他們的結果集合上執行排序及合併.然而,若是其中一個索引(EMP_TYPE)接近於惟一性而另外一個索引(EMP_CLASS)上有幾千個重複的值.排序及合併就會成爲一種沒必要要的負擔. 在這種狀況下,你但願使優化器屏蔽掉EMP_CLASS索引.
用下面的方案就能夠解決問題.
Select Ename
From Emp
Where Emp_Type = 'A'
And Emp_Class || ‘’ ='X';
WHERE子句中,若是索引列是函數的一部分.優化器將不使用索引而使用全表掃描.
舉例:
低效:
Select *From Dept
Where Sal * 12 >25000;
高效:
Select *From Dept
Where Sal > 25000 / 12;
注意:這是一個很是實用的規則,請務必牢記
若是表中有兩個以上(包括兩個)索引,其中有一個惟一性索引,而其餘是非惟一性.
在這種狀況下,ORACLE將使用惟一性索引而徹底忽略非惟一性索引.
舉例:
Select Ename
From Emp
Where Empno = 2326
And Deptno = 20;
這裏,只有EMPNO上的索引是惟一性的,因此EMPNO索引將用來檢索記錄.
TABLEACCESS BY ROWID ON EMP
INDEX UNIQUE SCAN ON EMP_NO_IDX
一般, 咱們要避免在索引列上使用NOT, NOT會產生在和在索引列上使用函數相同的
影響. 當ORACLE」遇到」NOT,他就會中止使用索引轉而執行全表掃描.
舉例:
低效: (這裏,不使用索引)
SELECT *FROM DEPT
WHERE DEPT_CODE NOT = 0;
高效: (這裏,使用了索引)
SELECT *FROM DEPT
WHERE DEPT_CODE > 0;
須要注意的是,在某些時候, ORACLE優化器會自動將NOT轉化成相對應的關係操做符.
NOT > to <=
NOT >= to <
NOT < to >=
NOT <= to >
注意:
在下面的這個測試例子中,故意犯了一些錯誤.例子中的低效率SQL是不能被執行的.
SQL> select * from emp where NOT empno > 1;
no rows selected
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
2 1 INDEX (RANGE SCAN) OF 'EMPNO' (UNIQUE)
SQL> select * from emp where empno <= 1;
no rows selected
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
2 1 INDEX (RANGE SCAN) OF 'EMPNO' (UNIQUE)
二者的效率徹底同樣,也許這符合關於」在某些時候, ORACLE優化器會自動將NOT轉化成相對應的關係操做符」的觀點.
Ø 避免在索引列上使用IS NULL和IS NOT NULL
避免在索引中使用任何能夠爲空的列,ORACLE將沒法使用該索引.對於單列索引,若是列包含空值,索引中將不存在此記錄.對於複合索引,若是每一個列都爲空,索引中一樣不存在此記錄. 若是至少有一個列不爲空,則記錄存在於索引中.
舉例:
若是惟一性索引創建在表的A列和B列上,而且表中存在一條記錄的A,B值爲(123,null) , ORACLE將不接受下一條具備相同A,B值(123,null)的記錄(插入).然而若是
全部的索引列都爲空,ORACLE將認爲整個鍵值爲空而空不等於空.所以你能夠插入1000
條具備相同鍵值的記錄,固然它們都是空!
由於空值不存在於索引列中,因此WHERE子句中對索引列進行空值比較將使ORACLE停用該索引.
舉例:
低效: (索引失效)
SELECT …
FROM DEPARTMENT
WHERE DEPT_CODE IS NOT NULL;
高效: (索引有效)
SELECT …
FROM DEPARTMENT
WHERE DEPT_CODE >=0;
若是索引是創建在多個列上,只有在它的第一個列(leading column)被where子句引用時,優化器纔會選擇使用該索引.
注意:這也是一條簡單而重要的規則.
見如下實例.
SQL> create table multiindexusage ( inda number , indb number , descr varchar2(10));
Table created.
SQL> create index multindex on multiindexusage(inda,indb);
Index created.
SQL> set autotrace traceonly
SQL> select * from multiindexusage where inda = 1;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'MULTIINDEXUSAGE'
2 1 INDEX (RANGE SCAN) OF 'MULTINDEX' (NON-UNIQUE)
SQL> select * from multiindexusage where indb = 1;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (FULL) OF 'MULTIINDEXUSAGE'
很明顯, 當僅引用索引的第二個列時,優化器使用了全表掃描而忽略了索引
這一部門主要介紹Oracle數據庫的管理和配置,內容主要是DBA平常的操做,做爲開發人員只要瞭解就能夠,會一些簡單的操做就行。
數據庫的備份分爲熱備份和冷備份,熱備份是指數據庫在線備份,即不關閉數據庫的狀況下;冷備份是指在關閉數據庫,直接備份數據文件。
熱備份:
Oracle支持三種方式類型的輸出:
l 表方式(T方式),將指定表的數據導出。
l 用戶方式(U方式),將指定用戶的全部對象及數據導出。
l 全庫方式(Full方式),瘵數據庫中的全部對象導出。
數據導入(Import)的過程是數據導出(Export)的逆過程,分別將數據文件導入數據庫和將數據庫數據導出到數據文件。
1 table model
1) backup one user's table
exp icdmain/icd rows=y indexes=n compress=n buffer=65536 feedback=100000 volsize=0 file=exp_icdmain_table_yyyymmdd.dmp log=exp_icdmain_table_yyyymmdd.log tables=icdmain.commoninformation,icdmain.serviceinfo,icdmain.dealinfo
2) recover all table
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n commit=y buffer=65536 feedback=100000 ignore=y volsize=0 file=exp_icdmain_table_yyyymmdd.dmp log=imp_icdmain_table_yyyymmdd.log
3) recover some table of all table
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n commit=y buffer=65536 feedback=100000 ignore=y volsize=0 file=exp_icdmain_table_yyyymmdd.dmp log=imp_icdmain_table_yyyymmdd.log tables=commoninformation,serviceinfo
2 user model
1) backup all someone's object
exp icdmain/icd rows=y indexes=n compress=n buffer=65536 feedback=100000 volsize=0 owner=icdmain file=exp_icdmain_user_yyyymmdd.dmp log=exp_icdmain_user_yyyymmdd.log
2) recover all someone's object
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n commit=y buffer=65536 feedback=100000 ignore=y volsize=0 file=exp_icdmain_user_yyyymmdd.dmp log=imp_icdmain_user_yyyymmdd.log
3) recover some table of all someone's object
imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n commit=y buffer=65536 feedback=100000 ignore=y volsize=0 file=exp_icdmain_user_yyyymmdd.dmp log=imp_icdmain_user_yyyymmdd.log tables=commoninformation,serviceinfo
3 full model
1)backup the full db for all
exp system/manager rows=y indexes=n compress=n buffer=65536 feedback=100000 volsize=0 full=y inctype=complete file=exp_fulldb_yyyymmdd.dmp log=exp_fulldb_yyyymmdd.log
2)backup the full db for zengliang
exp system/manager rows=y indexes=n compress=n buffer=65536 feedback=100000 volsize=0 full=y inctype=incremental file=exp_fulldb_zl_yyyymmdd.dmp log=exp_fulldb_zl_yyyymmdd.log
3)recover all date for full backup
imp system/manager rows=y indexes=n commit=y buffer=65536 feedback=100000 ignore=y volsize=0 full=y file=exp_fulldb_yyyymmdd.dmp log=imp_fulldb_yyyymmdd.log
4)recover all date for zengliang backup
imp system/manager rows=y indexes=n commit=y buffer=65536 feedback=100000 ignore=y volsize=0 full=y inctype=restore file=exp_fulldb_zl_yyyymmdd.dmp log=imp_fulldb_zl_yyyymmdd.log
shell腳本:
#backup_full.sh
rman target / cmdfile=/oracle/backup_full.rman
rman腳本全庫及數據庫歸檔日至進行全備份(backup_full.rman):
run{
allocate channel d1 device type disk;
backup database format '/oradata/backup/FULL_%T_%d_%U';
backup archivelog all delete input
format '/oradata/backup/full_%u_%p_%c.ac' filesperset = 3;
release channel d1;
}
exit;
#cron文件
0 12,18 * * * /bin/backup_full.sh
關於參數調整,是oracle的複雜性的一個具體體現。一般來說,咱們更傾向於讓客戶作
statspack 報告,而後告訴咱們os監控的情況,在這些的信息的基礎上,再向客戶索取具體
的詳細信息以診斷問題的所在。系統的調整,如今咱們一般採用從等待事件入手的方法。由於一個系統感受到慢,必然是在某個環節上出現等待,那麼咱們從等待最多的事件入手逐步診斷並解決問題。
ORACLE的最大鏈接數(sessions)與其參數文件中的進程數(process)有關,它們的關係以下:
sessions=(1.1*process+5)
查看當前鏈接數
SQL>select count(*) from v$ sessions;
查看oracle鏈接數設置
SQL>show parameter processes
修改最大鏈接數
SQL>alter system set processes=500 scope=spfile;
重啓數據庫生效
SQL> shutdown immediate;
SQL> startup;
對於內存的調整,相對來講簡單一些,咱們首先能夠針對數據緩衝區的大小來看。首先
觀察命中率。
數據緩衝區命中率
SQL> select value from v$sysstat where name ='physical reads';
VALUE
----------
14764
SQL> select value from v$sysstat where name ='physical reads direct';
VALUE
----------
50
SQL> select value from v$sysstat where name ='physical reads direct (lob)';
VALUE
----------
0
SQL> select value from v$sysstat where name ='consistent gets';
VALUE
----------
167763
假如 redo buffer allocation retries/ redo entries的比例超過1%咱們就能夠考慮增大log_buffer
一般來講,內存的調整的焦點就集中在這幾個方面,更多更詳細的內容,建議從statspack
入手來一步一步調整。最後關於內存的調整,再強調這一點,必定要結合操做系統來衡量,
任何理論都必需要實踐來檢驗。在操做系統中觀察 page in/out情況,發現問題嚴重,應
該考慮調小SGA。
查看SGA
SQL>select count(*) from v$ sessions;
--或
SQL> show parameter sga_max_size;
修改SAG
SQL> alter system set sga_max_size=500m scope=spfile;
重啓生效
對於oracle來講,存在着32bit與64bit的問題。這個問題影響到的主要是SGA的大小。
在32bit的數據庫下,一般oracle只能使用不超過1.7G的內存,即便咱們擁有12G的內存,
可是咱們卻只能使用1.7G,這是一個莫大的遺憾。假如咱們安裝64bit的數據庫,咱們就可使用很大的內存,幾乎不可能達到上限。可是64bit的數據庫必須安裝在64bit 的操做系統上,惋惜目前windows上只能安裝32bit的數據庫.對於linux操做系統下的數據庫,因爲在正常狀況下Oracle對SGA的管理能力不超過1.7G。因此總的物理內存在4G如下。SGA的大小爲物理內存的50%—75%。對於64位的小型系統,Oracle數據庫對SGA的管理超過2G的限制,SGA設計在一個合適的範圍內:物理內存的50%—70%,當SGA過大的時候會致使內存分頁,影響系統性能。
咱們經過下面的方式能夠查看數據庫是32bit仍是64bit:
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production
PL/SQL Release 8.1.7.0.0 - Production
CORE 8.1.7.0.0 Production
TNS for 32-bit Windows: Version 8.1.7.0.0 - Production
NLSRTL Version 3.4.1.0.0 – Production
假如是64bit oracle,在查詢結果中必定會顯示 64bit字樣,沒有出現,則必定是32bit oracle .固然,在os上經過file oracle也能看到
[oracle@ocn2 bin]$ cd $ORACLE_HOME/bin
[oracle@ocn2 bin]$ file oracle
oracle: setuid setgid ELF 32-bit LSB executable, Intel 80386, version 1, dynamically linked (uses shared libs), not stripped
可是在特定的操做系統下,可能提供了必定的手段,使得可使用超過1.7G的內
存,達到2G 以上甚至更多。在這裏咱們針對不一樣的平臺下的具體實現方式作一個總結。
hmmax內核參數定義單個共享內存段的最大值,若是該參數設置小於Oracle SGA設置,那麼SGA就會被分配多個共享內存段。這在繁忙的系統中可能成爲性能負擔,帶來系統問題。
Linux上該參數的缺省值一般爲32M。
[root@neirong root]# more /proc/sys/kernel/shmmax
33554432
能夠經過ipcs命令查看此設置下共享內存的分配,咱們能夠看到Oracle分配了多個共享內存段以知足SGA設置的須要:
[root@neirong root]# ipcs -sa
使用pmap咱們能夠看到每一個共享內存段的地址空間
[root@neirong root]# ps -ef|grep 3102
爲了不多個共享內存段,咱們能夠修改shmmax內核參數,使SGA存在於一個共享內存段中。
經過修改/proc/sys/kernel/shmmax參數能夠達到此目的。
[root@neirong root]# echo 1073741824 > /proc/sys/kernel/shmmax
[root@neirong root]# more /proc/sys/kernel/shmmax
1073741824
這裏設爲1G。
對於shmmax文件的修改,系統從新啓動後會復位。能夠經過修改 /etc/sysctl.conf使更改永久化。
在該文件內添加如下一行
這個更改在系統從新啓動後生效
kernel.shmmax = 1073741824
重起數據庫使更改生效:
SQL> shutdown immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> !
[oracle@neirong oracle]$ ipcs -sa
SQL> startup
此時進程的pmap映射顯示爲:
[oracle@neirong bdump]$ pmap 4178
實際上,若是沒有修改shmmax參數,Oracle在啓動過程當中就會報出如下錯誤:
Starting ORACLE instance (normal)
Thu Nov 17 09:27:29 2005
WARNING: EINVAL creating segment of size 0x0000000033400000
fix shm parameters in /etc/system or equivalent
此類問題的產生緣由通常都是由於系統中存在性能低下或者存在錯誤的SQL語句。
一、首先用經過Top命令來查看:
$ top
load averages: 1.61, 1.28, 1.25 HSWAPJSDB 10:50:44
172 processes: 160 sleeping, 1 running, 3 zombie, 6 stopped, 2 on cpu
CPU states: % idle, % user, % kernel, % iowait, % swap
Memory: 4.0G real, 1.4G free, 1.9G swap in use, 8.9G swap free
PID USERNAME THR PR NCE SIZE RES STATE TIME FLTS CPU COMMAND
20521 oracle 1 40 0 1.8G 1.7G run 6:37 0 47.77% oracle
20845 oracle 1 40 0 1.8G 1.7G cpu02 0:41 0 40.98% oracle
20847 oracle 1 58 0 1.8G 1.7G sleep 0:00 0 0.84% oracle
20780 oracle 1 48 0 1.8G 1.7G sleep 0:02 0 0.83% oracle
15828 oracle 1 58 0 1.8G 1.7G sleep 0:58 0 0.53% oracle
20867 root 1 58 0 4384K 2560K sleep 0:00 0 0.29% sshd2
20493 oracle 1 58 0 1.8G 1.7G sleep 0:03 0 0.29% oracle
20887 oracle 1 48 0 1.8G 1.7G sleep 0:00 0 0.13% oracle
20851 oracle 1 58 0 1.8G 1.7G sleep 0:00 0 0.10% oracle
20483 oracle 1 48 0 1.8G 1.7G sleep 0:00 0 0.09% oracle
20875 oracle 1 45 0 1064K 896K sleep 0:00 0 0.07% sh
20794 oracle 1 58 0 1.8G 1.7G sleep 0:00 0 0.06% oracle
20842 jiankong 1 52 2 1224K 896K sleep 0:00 0 0.05% sadc
20888 oracle 1 55 0 1712K 1272K cpu00 0:00 0 0.05% top
19954 oracle 1 58 0 1.8G 1.7G sleep 84:25 0 0.04% oracle
註釋:如今能夠發如今進程列表裏,存在兩個高CPU耗用的Oracle進程,他們分別消耗了47.77%和40.98%的CPU資源。
二、下一步找到存在問題的進程信息,以此確認它們是兩個遠程鏈接的用戶進程。
$ ps -ef|grep 20521
oracle 20909 20875 0 10:50:53 pts/10 0:00 grep 20521
oracle 20521 1 47 10:43:59 ? 6:45 oraclejshs (LOCAL=NO)
$ ps -ef|grep 20845
oracle 20845 1 44 10:50:00 ? 0:55 oraclejshs (LOCAL=NO)
oracle 20918 20875 0 10:50:59 pts/10 0:00 grep 20845
三、下面咱們再來看一下getsql.sql腳本
SELECT /*+ ORDERED */
sql_text
FROM v$sqltext a
WHERE (a.hash_value, a.address) IN (
SELECT DECODE (sql_hash_value,
0, prev_hash_value,
sql_hash_value
),
DECODE (sql_hash_value, 0, prev_sql_addr, sql_address)
FROM v$session b
WHERE b.paddr = (SELECT addr
FROM v$process c
WHERE c.spid = '&pid'))
ORDER BY piece ASC
/
註釋:在此部分咱們涉及了3個視圖,並應用其關聯進行數據獲取。首先咱們須要輸入一個pid,這個pid就是process id,也就是咱們在Top或ps中咱們看到的PID.
注意,經過pid和v$process.spid相關聯咱們能夠得到Process的相關信息,進而經過v$process.addr和v$session.paddr相關聯,咱們便可以得到和session相關的全部信息。
而後再結合v$sqltext,就能夠得到當前session正在執行的SQL語句。
經過v$process視圖,咱們就以把操做系統和數據庫關聯起來了。
四、下面,咱們來鏈接數據庫,找到問題sql及進程
註釋:經過Top中咱們觀察到的PID,進而應用個人getsql腳本,獲得瞭如下結果輸出。
此時咱們就能夠作出結論,這段代碼就是當前正在肆意消耗CPU的元兇。
下面咱們須要找出這段代碼的問題,看一看是否能夠經過優化來提升其效率,減小資源消耗。
五、下一步則能夠經過dbms_system包來跟蹤該進程
SQL> @getsid
Enter value for spid: 20521
old 3: select addr from v$process where spid = &spid)
new 3: select addr from v$process where spid = 20521)
SID SERIAL# USERNAME MACHINE
----------------------------------------------------------------
45 38991 HSUSER_V51 hswapjsptl1.hurray.com.cn
SQL> exec dbms_system.set_sql_trace_in_session(45,38991,true);
PL/SQL procedure successfully completed.
SQL> !
多個表空間的優點:
l 可以將數據字典與用戶數據分離出來,避免因爲字典對象和用戶對象保存在同一個數據文件中而產生的I/O衝突
l 可以將回退數據與用戶數據分離出來,避免因爲硬盤損壞而致使永久性的數據丟失
l 可以將表空間的數據文件分散保存到不一樣的硬盤上,平均分佈物理I/O操做
l 可以將某個表空間設置爲脫機狀態或聯機狀態,以便對數據庫的一部分進行備份和恢復
l 可以將某個表空間設置爲只讀狀態,從而將數據庫的一部分設置爲只讀狀態
l 可以爲某種特殊用途專門設置一個表空間,好比臨時表空間等,以優化表空間的使用效率
l 可以更佳靈活的爲用戶設置表空間限額
SYSTEM表空間內存儲:
l 數據庫的數據字典
l 全部PL/SQL程序的源代碼和解析代碼
l 數據庫對象的定義
表空間數據字典
l v$tablespace 控制文件中獲取的表空間的名稱和編號信息
l v$datafile 控制文件中獲取的數據文件的名稱和編號信息
l v$tempfile 全部臨時數據文件的基本信息
l v$sort_segment 實例所建立的排序區的信息
l v$sort_user 排序區的用戶使用狀況信息
l dba_tablespaces 數據庫中表空間的名稱和編號信息
l dba_segments 表空間中段的信息
l dba_extents 表空間中區的信息
l dba_free_space 表空間中空閒區的信息
l dba_data_files 數據文件亦即所屬表空間的信息
l dba_temp_files 臨時數據文件亦即所屬表空間的信息
--單數據文件
createtablespace dmusertbs
datafile 'i:\oracle\oradata\dmusertbs.dbf'size 50M
autoextendon
next 5M
maxsize 500M;
(next參數指定每次自動增加的大小,maxsize爲數據文件的最大大小);
--多數據數據文件
createtablespace dmusertbs
datafile 'i:\oracle\oradata\dmusertbs01.dbf'size 50M,
'i:\oracle\oradata\dmusertbs02.dbf'size 50M,
'i:\oracle\oradata\dmusertbs03.dbf'size 50M;
--恢復表空間爲聯機狀態
alter tablespace user01 online;
--設置表空間爲只讀狀態
alter tablespace user01 read only
--設置表空間爲讀寫狀態
alter tablespace user01 read write
--刪除表空間(不包括對應的數據文件)
drop tablespace users including contents;
--刪除表空間(包括對應的數據文件)
drop tablespace users including contents and datafiles;
數據文件數據字典
l DBA_DATA_FILES 數據庫中全部數據文件的信息
l DBA_TEMP_FILES 數據庫中全部臨時數據文件的信息
l DBA_EXTENTS 表空間中已分配的區的描述信息,包括區所屬的數據文件的編號
l DBA_FREE_SPACE 表空間中空閒區的信息
-- 在表空間lmusertbs上添加一個自動增加方式的數據文件
alter tablespace lmusertbs
add datafile 'i:\oracle\oradata\lmusertbs02.dbf'size 50M
autoextend on
next 5M
maxsize 500M;
-- 若是數據文件已經建立,將它設置成自動增加方式
alter database
datafile 'i:\oracle\oradata\dmusertbs01.dbf'
autoextend on
next 5M
maxsize 500M;
--取消已有數據文件的自動增加方式
alter database
datafile 'i:\oracle\oradata\dmusertbs01.dbf'
autoextend off;
--手工改變數據文件的大小:將數據文件dmusertbs01.dbf增大爲500MB
alter database datafile 'i:\oracle\oradata\dmusertbs01.dbf'resize 500M;
Select Tablespace_Name,
Sum_m,
Max_m,
Count_Blocks Free_Blk_Cnt,
Sum_Free_m,
To_Char(100 * Sum_Free_m / Sum_m,'99.99') || '%' As Pct_Free
From (Select Tablespace_Name, Sum(Bytes) / 1024 /1024 As Sum_m
From Dba_Data_Files
Group By Tablespace_Name)
Left Join (Select Tablespace_Name As Fs_Ts_Name,
Max(Bytes) / 1024 /1024 As Max_m,
Count(Blocks) As Count_Blocks,
Sum(Bytes / 1024 /1024) As Sum_Free_m
From Dba_Free_Space
Group By Tablespace_Name) On Tablespace_Name = Fs_Ts_Name;
若是表空間已滿,能夠改變數據文件大小或增長數據文件。