2010年4月15日 星期四

Ado.net Connect Pool by ConnectionString Test

Environment:
DB : SQL Server 2008
client framework : .Net Framework 3.5


Test Code:
Case1 : use connection pool, 3000 times select table

SqlConnection sqlconn = new SqlConnection();
sqlconn.ConnectionString = "Network Library=DBMSSOCN;Data Source=serverip,port;
Initial Catalog=wgs;User ID=your id; Password=your password;"+
"Min Pool Size=0; Max Pool Size=8;
Connection Timeout=3;Connection Lifetime=10";
//"Pooling=false; Connect Timeout=3";
string queryString = "SELECT * FROM dbo.yourtable;";
//Console.WriteLine("State: {0}", sqlconn.ConnectionString);
SqlCommand command = new SqlCommand(queryString, sqlconn);

DateTime beging = DateTime.Now;
int n = 0;
while (n < 3000) {
sqlconn.Open();
SqlDataReader reader = command.ExecuteReader();
try
{
while (reader.Read())
{
//Console.WriteLine(String.Format("{0}, {1}", reader[0], reader[1]));
}
}
finally
{
// Always call Close when done reading.
reader.Close();
}
n=n+1;
sqlconn.Close();
//Console.WriteLine("State: {0}", sqlconn.State);
}
DateTime end = DateTime.Now;
Console.WriteLine("Cost Time: {0}", end.Subtract(beging));

Case2 :don't use connection pool, 3000 times select table
SqlConnection sqlconn = new SqlConnection();
sqlconn.ConnectionString = "Network Library=DBMSSOCN;Data Source=serverip,port;
Initial Catalog=wgs;User ID=your id; Password=your password;"+
"Pooling=false; Connect Timeout=3";
string queryString = "SELECT * FROM dbo.yourtable;";
//Console.WriteLine("State: {0}", sqlconn.ConnectionString);
SqlCommand command = new SqlCommand(queryString, sqlconn);

DateTime beging = DateTime.Now;
int n = 0;
while (n < 3000) {
sqlconn.Open();
SqlDataReader reader = command.ExecuteReader();
try
{
while (reader.Read())
{
//Console.WriteLine(String.Format("{0}, {1}", reader[0], reader[1]));
}
}
finally
{
// Always call Close when done reading.
reader.Close();
}
n=n+1;
sqlconn.Close();
//Console.WriteLine("State: {0}", sqlconn.State);
}
DateTime end = DateTime.Now;
Console.WriteLine("Cost Time: {0}", end.Subtract(beging));

Conclusion:
Case1: cost 4.1~.4.3 seconds.
Case2: cost up 25 seconds.

Using Connection Pool is a good solution.

2010年1月28日 星期四

.Net Framework Provider for Oacle

最近有需求在.net(C#) + oracle 環境 加上Connection Pool,
在網路上用google大神,仔細比較了幾種方式:
1.Oracle 提供的 Interface or API
2.Vender 寫的Client呼叫 Oracle的


為了有 connection pool 機制,又可以用OCI,所選擇的連線方式:

使用 Oracle 的 .NET Framework 資料提供者

Oracle 的 .NET Framework 資料提供者利用由 Oracle 用戶端軟體所提供的「Oracle 呼叫介面 (OCI)」,來存取 Oracle 資料庫。

Oracle 的 .NET Framework 資料提供者系統需求
Oracle 的 .NET Framework 資料提供者需要 Microsoft Data Access Components (MDAC) 2.6 (含) 以後版本。建議使用 MDAC 2.8 SP1。
您還必須安裝 Oracle 8i 3 版 (8.1.7) 用戶端 (含) 以後版本。
Oracle 9i 版之前的 Oracle 用戶端軟體無法存取 UTF16 資料庫,因為 UTF16 是 Oracle 9i 的新功能。若要使用此功能,您必須將用戶端軟體升級至 Oracle 9i (含) 以後版本。

Connection Pooling for the .NET Framework Data Provider for Oracle
Enlisting in Distributed Transactions
OracleConnection.ConnectionString Property

2010年1月27日 星期三

Oracle Connection Pool integrate with Microsoft .Net

List all methods of .net connection to oralce , then choice one which has connection pool.


Oracle Database on Windows and .NET FAQ
Oracle offers a variety of data access methods for COM-based, .NET-based, and Win32/64-based programming languages. Oracle developers can use any one of the following data access drivers based on the Windows programming language employed:

.NET: Oracle Data Provider for .NET, OLE DB.NET via Oracle Provider for OLE DB, ODBC.NET via Oracle ODBC Driver
COM: Oracle Objects for OLE (OO4O), Oracle Provider for OLE DB via Microsoft's ActiveX Data Objects (ADO)
PL/SQL and Java (server-side programming) to COM Automation servers (e.g. Microsoft Office): COM Automation Feature
Win32/64: ODBC Driver, Oracle Call Interface (OCI), Oracle Provider for OLE DB


Pooling=>
Solution 1
Oracle Data Provider.NET (ODP) and built a C# window service.
Getting Started with Oracle Data Provider for .NET (C# Version)
Solution 2
Connection Pooling in ADO .NET
reference from Connection Pooling in ADO .NET

ODBC V.S. OLEDB V.S. ODP Performance
reference from here
Oracle odbc 插入一萬筆要51秒,而OleDB只要14秒,用Oracle donet client 只要八秒


MDAC Architecture

2009年1月5日 星期一

Oracle Net Configure Setting

來源:http://bbs.loveunix.net/blog.php?tid=56050&starttime=0&endtime=0

以下內容來之Internet,不知道原作者是哪位了,非常感謝作者的總結。
版權歸原作者。

最近看到好多人說到tns或者數據庫不能登錄等問題,就索性總結了下面的文檔。

首先來說Oracle的網絡結構,往複雜處說能加上加密、LDAP等等。。這裡不做討論,重點放在基本的網絡結構也就是我們最常用的這種情況

三個配置文件
  listener.ora、 sqlnet.ora、tnsnames.ora ,都是放在$ORACLE_HOME\network\admin目錄下。
  重點:三個文件的作用和使用


  sqlnet.ora-- ---作用類似於 linux或者其他unix的nsswitch.conf文件,通過這個文件來決定怎麼樣找一個連接中出現的連接字符串,  

  例如我們客戶端輸入
   sqlplus sys/oracle@orcl  

  假如我的sqlnet.ora是下面這個樣子  

   SQLNET.AUTHENTICATION_SERVICES= (NTS)
   NAMES.DIRECTORY_PATH= (TNSNAMES,HOSTNAME)  

  那麼,客戶端就會首先在tnsnames.ora文件中找orcl的記錄.如果沒有相應的記錄則嘗試把orcl當作一個主機名,通過網絡的途徑去解析它的ip地址然後去連接這個ip上GLOBAL_DBNAME=orcl這個實例,當然我這裡orcl並不是一個主機名  

  如果我是這個樣子
   NAMES.DIRECTORY_PATH= (TNSNAMES)
  那麼客戶端就只會從tnsnames.ora查找orcl的記錄  

  括號中還有其他選項,如LDAP等並不常用。 
  

  Tnsnames.ora-- ----這個文件類似於unix 的hosts文件,提供的tnsname到主機名或者ip的對應,只有當 sqlnet.ora中類似
  NAMES.DIRECTORY_PATH= (TNSNAMES) 這樣,也就是客戶端解析連接字符串的順序中有TNSNAMES是,才會嘗試使用這個文件。
  例子中有兩個,ORCL 對應的本機,SALES對應的另外一個IP地址,裡邊還定義了使用主用服務器還是共享服務器模式進行連接,一句一句說
  #你所要連接的時候輸入得TNSNAME

ORCL =
  (DESCRIPTION =
  (ADDRESS_LIST =  
  #下面是這個TNSNAME對應的主機,端口,協議  
   (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521))  
  )  
  (CONNECT_DATA =

  #使用專用服務器模式去連接需要跟服務器的模式匹配,如果沒有就根據服務器的模式  

  #自動調節
  (SERVER = DEDICATED) 

  #對應service_name,SQLPLUS>show parameter service_name;

  #進行查看  
  (SERVICE_NAME = orcl)  
   )  
  )
 

  #下面這個類似  
  SALES =  
  (DESCRIPTION =  
  (ADDRESS_LIST =  
   (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.188.219)(PORT = 1521))  
  )  
  (CONNECT_DATA =  
  (SERVER = DEDICATED)  
  (SERVICE_NAME = sales)  
  )  
  )

  客戶端完了我們來看服務器端
  listener.ora------listener 監聽器進程的配置文件
  關於listener進程就不多說了,接受遠程對數據庫的接入申請並轉交給oracle的服務器進程。所以如果不是使用的遠程的連接, listener進程就不是必需的,同樣的如果關閉listener進程並不會影響已經存在的數據庫連接。
  Listener.ora文件的例子
  #listener.ora Network Configuration File: #E:\oracle\product\10.1.0\Db_2\NETWORK\ADMIN\listener.ora
  # Generated by Oracle configuration tools.
  #下面定義LISTENER進程為哪個實例提供服務
  #這裡是ORCL,並且它對應的ORACLE_HOME和GLOBAL_DBNAME
  #其中GLOBAL_DBNAME不是必需的除非使用HOSTNAME做數據庫連接
   SID_LIST_LISTENER =  
  (SID_LIST =  
  (SID_DESC =  
  (GLOBAL_DBNAME = boway)  
  (ORACLE_HOME = E:\oracle\product\10.1.0\Db_2)  
  (SID_NAME = ORCL)  
  )  
  )  

  #監聽器的名字,一台數據庫可以有不止一個監聽器
  #再向下面是監聽器監聽的協議,ip,端口等,這裡使用的tcp1521端口,並且使#用的是主機名
   LISTENER =  
  (DESCRIPTION =  
  (ADDRESS = (PROTOCOL = TCP)(HOST = boway)(PORT = 1521))  
  )

  上面的例子是一個最簡單的例子,但也是最普遍的。一個listener進程為一個instance(SID) 提供服務。  

  監聽器的操作命令
  $ORACLE_HOME/bin/lsnrctl start,其他諸如stop,status等。具體敲完一個lsnrctl後看幫助。
  

  上面說到的三個文件都可以通過圖形的配置工具來完成配置
  $ORACLE_HOME/netca 嚮導形式的
  $ORACLE_HOME/netmgr  

  本人比較習慣netmgr,

  profile 配置的是sqlnet.ora也就是名稱解析的方式
  service name 配置的是tnsnames.ora文件
  listeners配置的是listener.ora文件,即監聽器進程 

  具體的配置可以嘗試一下然後來看一下配置文件。  

  這樣一來總體結構就有了,是當你輸入sqlplus sys/oracle@orcl的時候
  1. 查詢sqlnet.ora看看名稱的解析方式,發現是TNSNAME
  2. 則查詢tnsnames.ora文件,從裡邊找orcl的記錄,並且找到主機名,端口和service_name
  3. 如果listener進程沒有問題的話,建立與listener進程的連接。
  4. 根據不同的服務器模式如專用服務器模式或者共享服務器模式,listener採取接下去的動作。默認是專用服務器模式,沒有問題的話客戶端就連接上了數據庫的server process。
  5. 這時候網絡連接已經建立,listener進程的歷史使命也就完成了。



  幾種連接用到的命令形式
  1.sqlplus / as sysdba 這是典型的操作系統認證,不需要listener進程
  2.sqlplus sys/oracle 這種連接方式只能連接本機數據庫,同樣不需要listener進程
  3.sqlplus sys/oracle@orcl 這種方式需要listener進程處於可用狀態。最普遍的通過網絡連接。

  以上連接方式使用sys用戶或者其他通過密碼文件驗證的用戶都不需要數據庫處於可用狀態,操作系統認證也不需要數據庫可用,普通用戶因為是數據庫認證,所以數據庫必需處於open狀態。


  平時排錯可能會用到的
  1.lsnrctl status查看服務器端listener進程的狀態
  LSNRCTL> help
   The following operations are available 
  An asterisk (*) denotes a modifier or extended command:
 start stop status
  services version reload
  save_config trace change_password
 quit exit set*
   show* 
   LSNRCTL> status

  2.tnsping 查看客戶端sqlnet.ora和tnsname.ora文件的配置正確與否,及對應的服務器的listener進程的狀態。
  C:\>tnsping orcl
  TNS Ping Utility for 32-bit Windows: Version 10.1.0.2.0 - Production on 16-8月 -2005 09:36:08
  Copyright (c) 1997, 2003, Oracle. All rights reserved.
  Used parameter files:
  E:\oracle\product\10.1.0\Db_2\network\admin\sqlnet.ora
  Used TNSNAMES adapter to resolve the alias
  Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)
  (HOST = 127.0.0.1)(PORT = 1521))) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orcl))) 

  OK (20 msec)

  3.
  SQL>show sga 查看instance是否已經啟動
  SQL> select open_mode from v$database; 查看數據庫是打開還是mount狀態。
  OPEN_MODE 
  ---------- 
  READ WRITE  


  使用hostname訪問數據庫而不是tnsname的例子
  使用tnsname訪問數據庫是默認的方式,但是也帶來點問題,那就是客戶端都是需要配置tnsnames.ora文件的。如果你的數據庫服務器地址發生改變,就需要重新編輯客戶端這個文件。通過hostname訪問數據庫就沒有了這個麻煩。
  需要修改
  服務器端listener.ora
  #監聽器的配置文件listener.ora
  #使用host naming則不再需要tnsname.ora文件做本地解析
  # listener.ora Network Configuration File: d:\oracle\product\10.1.0\db_1\NETWORK\ADMIN\listener.ora
  # Generated by Oracle configuration tools. 
 SID_LIST_LISTENER =
 (SID_LIST =
  (SID_DESC =
  # (SID_NAME = PLSExtProc)
  (SID_NAME = orcl)
  (GLOBAL_DBNAME = boway)
  (ORACLE_HOME = d:\oracle\product\10.1.0\db_1)
  # (PROGRAM = extproc)
  )
  )
   LISTENER =
  (DESCRIPTION_LIST =
  (DESCRIPTION =
   (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC))
  )
  (DESCRIPTION =
   (ADDRESS = (PROTOCOL = TCP)(HOST = boway)(PORT = 1521))  
 )  
 )

  客戶端sqlnet.ora 如果確認不會使用TNSNAME訪問的話,可以去掉TNSNAMES
  # sqlnet.ora Network Configuration File: d:\oracle\product\10.1.0\db_1\NETWORK\ADMIN\sqlnet.ora
  # Generated by Oracle configuration tools.
   SQLNET.AUTHENTICATION_SERVICES= (NTS)
   NAMES.DIRECTORY_PATH= (HOSTNAME)
  Tnsnames.ora文件不需要配置,刪除也無所謂。

  下面就是網絡和操作系統的配置問題了,怎麼樣能夠解析我的主機名的問題了
  可以通過下面的方式連接
  sqlplus sys/oracle@boway
  這樣的話,會連接boway這台服務器,並且listener來確定你所要連接的service_name。



簡單來說,以conn hr/hr@abc 為例

abc是我們連接遠端數據庫用到的服務命名,但是最終必須轉化為host:port:sid這樣的連接字串,而這個轉化可以理解為是翻譯的過程,而要想翻
譯成功,則必須選擇好翻譯方法,那麼sqlnet.ora就是我們用來選擇翻譯方法的,其中的NAMES.DIRECTORY_PATH=
(TNSNAMES,HOSTNAME) 就是我們選擇的命名解析方法;
tnsnames.ora是翻譯方法中的一種——本地命名解析方法的配置文件,就好像我們選擇了查字典方法,這個文件就是我們的字典一樣裡面存放著所有服
務命名對應的連接字串;至於listener.ora則是負責接受我們請求的負責任人連接地址配置文件,裡麵包括了連接負責人的連接地址,也放著經過他允
許可以連接的數據庫信息。這樣就構成了Oracle的網絡架構。

2008年12月3日 星期三



Creating Tablespace



CREATE TABLESPACE userdata
DATAFILE '/u01/oradata/userdata01.dbf' SIZE 100M
AUTOEXTEND ON NEXT 5M MAXSIZE 200M;





Creating User



CREATE USER tester
IDENTIFIED BY sysdba
DEFAULT TABLESPACE userdata
TEMPORARY TABLESPACE temp
QUOTA 15m ON userdata
PASSWORD EXPIRE;




Crant User



GRANT CREATE SESSION TO tester;

2008年10月29日 星期三

ORA-01102: cannot mount database in EXCLUSIVE mode

出處一:
http://www.dba-oracle.com/t_ora_01102_cannot_mount_database_in_exclusive_mode.htm

********************************

http://www.orafaq.com/forum/t/40030/0/

database is started in EXCLUSIVE mode by default. Therefore, the
ORA-01102 error is misleading and may have occurred due to one of the
following reasons:

- there is still an "sgadef.dbf" file in the "ORACLE_HOME/dbs"
directory
- the processes for Oracle (pmon, smon, lgwr and dbwr) still exist
- shared memory segments and semaphores still exist even though the
database has been shutdown
- there is a "ORACLE_HOME/dbs/lk" file

The "lk" and "sgadef.dbf" files are used for locking shared memory.
It seems that even though no memory is allocated, Oracle thinks memory is
still locked. By removing the "sgadef" and "lk" files you remove any knowledge
oracle has of shared memory that is in use. Now the database can start.

POSSIBLE SOLUTION:
Verify that the database was shutdown cleanly by doing the following:

1. Verify that there is not a "sgadef.dbf" file in the directory
"ORACLE_HOME/dbs".

% ls $ORACLE_HOME/dbs/sgadef.dbf

If this file does exist, remove it.

% rm $ORACLE_HOME/dbs/sgadef.dbf

2. Verify that there are no background processes owned by "oracle"

% ps -ef | grep ora_ | grep $ORACLE_SID

If background processes exist, remove them by using the Unix
command "kill". For example:

% kill -9

3. Verify that no shared memory segments and semaphores that are owned
by "oracle" still exist

% ipcs -b

If there are shared memory segments and semaphores owned by "oracle",
remove the shared memory segments

% ipcrm -m

and remove the semaphores

% ipcrm -s

NOTE: The example shown above assumes that you only have one
database on this machine. If you have more than one
database, you will need to shutdown all other databases
before proceeding with Step 4.

4. Verify that the "$ORACLE_HOME/dbs/lk" file does not exist

5. Startup the instance

//////////////////////////////////////

出處二
http://www.dbifan.com/?p=248

ORA-01102: cannot mount database in EXCLUSIVE mode

今天在STARTUP一数据库时,发生如下错误:

SQL> conn /as sysdba
Connected to an idle instance.
SQL> startup
ORACLE instance started.

Total System Global Area 276824064 bytes
Fixed Size 778736 bytes
Variable Size 137371152 bytes
Database Buffers 138412032 bytes
Redo Buffers 262144 bytes
ORA-01102: cannot mount database in EXCLUSIVE mode

SQL> shutdown immediate
ORA-01507: database not mounted

ORACLE instance shut down.

GOOGLE一下,发现是lk文件造成的,该文件位于ORALCE_HOME下的dbs目录下,马上检查该文件:

[root@qa-oracle dbs]# fuser -u lkNDMSQA
lkNDMSQA: 6666(oracle) 6668(oracle) 6670(oracle) 6672(oracle) 6674(oracle) 6676(oracle) 6678(oracle) 6680(oracle) 6690(oracle) 6692(oracle) 6694(oracle) 6696(oracle) 6737(oracle) 6830(oracle)

果然该文件没释放,用fuser命令kill掉:

[root@qa-oracle dbs]# fuser -k lkNDMSQA
lkNDMSQA: 6666 6668 6670 6672 6674 6676 6678 6680 6690 6692 6694 6696 6737 6830
[root@qa-oracle dbs]# fuser -u lkNDMSQA

然后:

SQL> startup
ORACLE instance started.

Total System Global Area 276824064 bytes
Fixed Size 778736 bytes
Variable Size 137371152 bytes
Database Buffers 138412032 bytes
Redo Buffers 262144 bytes
Database mounted.
Database opened.
SQL>

数据库成功OPEN.

关于该错误更详细的介绍如下:原文链接:http://www.hellodba.com/cases/case-unexception_down.htm

数据库异常关闭后无法启动问题处理一例

作者: fuyuncat

来源: www.HelloDBA.com

某系统突然掉电,系统启动后发现Oracle无法启动。启动时报如下错误:

ORA-01102 cannot mount database in EXCLUSIVE mode
出现1102错误可能有以下几种可能:

一、在HA系统中,已经有其他节点启动了实例,将双机共享的资源(如磁盘阵列上的裸设备)占用了;

二、说明Oracle被异常关闭时,有资源没有被释放,一般有以下几种可能,

1、 Oracle的共享内存段或信号量没有被释放;

2、 Oracle的后台进程(如SMON、PMON、DBWn等)没有被关闭;

3、 用于锁内存的文件lk和sgadef.dbf文件没有被删除。

首先,虽然我们的系统是HA系统,但是备节点的实例始终处在关闭状态,这点通过在备节点上查数据库状态可以证实。

其次、是因系统掉电引起数据库宕机的,系统在接电后被重启,因此我们排除了第二种可能种的1、2点。最可疑的就是第3点了。

查$ORACLE_HOME/dbs目录:

$ cd $ORACLE_HOME/dbs
$ ls sgadef*
sgadef* not found
$ ls lk*
lkORA92
果然,lk文件没有被删除。将它删除掉

$ rm lk*
再启动数据库,成功。

如果怀疑是共享内存没有被释放,可以用以下命令查看:

$ipcs -mop
IPC status from /dev/kmem as of Thu Jul 6 14:41:43 2006
T ID KEY MODE OWNER GROUP NATTCH CPID LPID
Shared Memory:
m 0 0×411c29d6 –rw-rw-rw- root root 0 899 899
m 1 0×4e0c0002 –rw-rw-rw- root root 2 899 901
m 2 0×4120007a –rw-rw-rw- root root 2 899 901
m 458755 0×0c6629c9 –rw-r—– root sys 2 9113 17065
m 4 0×06347849 –rw-rw-rw- root root 1 1661 9150
m 65541 0xffffffff –rw-r–r– root root 0 1659 1659
m 524294 0×5e100011 –rw——- root root 1 1811 1811
m 851975 0×5fe48aa4 –rw-r—– oracle oinstall 66 2017 25076
然后它ID号清除共享内存段:

$ipcrm –m 851975
对于信号量,可以用以下命令查看:

$ ipcs -sop
IPC status from /dev/kmem as of Thu Jul 6 14:44:16 2006
T ID KEY MODE OWNER GROUP
Semaphores:
s 0 0×4f1c0139 –ra——- root root
… …
s 14 0×6c200ad8 –ra-ra-ra- root root
s 15 0×6d200ad8 –ra-ra-ra- root root
s 16 0×6f200ad8 –ra-ra-ra- root root
s 17 0xffffffff –ra-r–r– root root
s 18 0×410c05c7 –ra-ra-ra- root root
s 19 0×00446f6e –ra-r–r– root root
s 20 0×00446f6d –ra-r–r– root root
s 21 0×00000001 –ra-ra-ra- root root
s 45078 0×67e72b58 –ra-r—– oracle oinstall
根据信号量ID,用以下命令清除信号量:

$ipcrm -s 45078
如果是Oracle进程没有关闭,用以下命令查出存在的oracle进程:

$ ps -ef|grep ora
oracle 29976 1 0 Jun 22 ? 0:52 ora_dbw0_ora92
oracle 29978 1 0 Jun 22 ? 0:51 ora_dbw1_ora92
oracle 5128 1 0 Jul 5 ? 0:00 oracleora92 (LOCAL=NO)
… …
然后用kill -9命令杀掉进程

$kill -9
总结:

当发生1102错误时,可以按照以下流程检查、排错:

1.如果是HA系统,检查其他节点是否已经启动实例;
2.检查Oracle进程是否存在,如果存在则杀掉进程;
3.检查信号量是否存在,如果存在,则清除信号量;
4.检查共享内存段是否存在,如果存在,则清除共享内存段;
5.检查锁内存文件lk和sgadef.dbf是否存在,如果存在,则删除。

2008年7月18日 星期五

Pool Module

sqlrelay
mysql_proxy

2008年7月11日 星期五

Using MySQL with memcached

http://dev.mysql.com/doc/refman/5.0/en/ha-memcached.html

2008年7月8日 星期二

Oracle Backup Recovery Solutions

http://www.qudong.com/soft/program/Oracle/shujuguanli/20080319/2537.html

http://www.qudong.com/soft/program/Oracle/shujuguanli/list_155_2.html

DBA Task

1.Evaluate Server and Install
2.Plan,Implement,Create,Open Database
3.Security (User and Database)
4.Tuning (SQL and Performance)
5.Backup and Recovery
6.Other : AP,RAC,TOOLS,STREAM,DATA GUARD

2008年6月13日 星期五

select * from goods_file
AS OF TIMESTAMP timestamp'2008-06-12 14:53:47'
where g_no = 11080531367948

2008年6月11日 星期三

Oracle DBCA (Database Configuration Assistant)

Template
1.Data Warehouse
2.Transaction Processing
3.General Purpose


1.Dedicated Server Mode
2.Shared Server Mode

Reset SYS , SYSTEM account default password.

Oracle Instance
1.System Global Area
SGA_MAX_SIZE , DB_CACHE_SIZE , LOG_BUFFER , SHARED_POOL_SIZE , LARGE_POOL_SIZE
2.Background processes

Data Cache Buffer
1.Write List (dirty buffers wait for write to disk)
2.LRU list (free , dirty , pinned buffers)
LRU Least Recently Used
MRU Most Recently Used

Total Size = DB_BLOCK_SIZE(2~32KB) * DB_BLOCK_BUFFERS

Redo Log Buffer (bytes)
Default : Redo Log Buffer = 4 * System Block Size

Share Pool (SHARED_POOL_SIZE = 8 MB in 32-bit , 6 MB in 64-bit system )
1. Library cache
Share SQL Area (SQL parse tree , execution plan)
Private SQL Area
PL/SQL Program Unit
2. Dictionary cache
parse information like table , view name , column name , data type
user privileges

DBWn - Database Writer
write dirty blocks from Data Cache Buffer to data files. => checkpoint
default only DBW0
btw in OLTP , update busy
DBW1~DBW9 is prefered.


LGWR - Log Writer
Write to redo log files
When
1. transaction commited
2. Auto Writing each 3 seconds.
3. free size of Redo log buffer is less than 1/3.
4. Before DBWn write dirty blocks to data files
Write - ahead protocol :
if LGWR write Redo data to redo logs finished
DBWn write dirty blocks to data files
else
Call LGWR write Redo data to redo logs
Then DBWn do its work.

SMON - System Monitor
Database Start Recovery checking
1. After Database restart , nessesary recovery activities.
2. Release not used temporary segments.
3. Collect and manage free extents
4. Recovery abort transaction.

PMON - Process Monitor
1. Recovery abort Process
2. Clear Data Buffer cache Unused block, reset transaction table status,
Unlock row , remove terminated process ID.

CKPT - Checkpoint
1. make sure MRU Dirty Data will write to data file regularly.
2. when instance recovery , can ignore the record before the currently checkpoint.
3. if(checkpoint finished)
CKPT call DBWn;
Then update control file and header of data file.
RECO (Recover)
handle transaction in Cluster database.
in-doubt transaction . transaction between servers.

ARCn (Archiver) (LOG_ARCHIVE_MAX_PROCESSES LIMIT IS 10 OR ALTER SYSTEM to change)
log switch. Archived logs.
indeed, Oracle will judge it automatically.

2008年6月9日 星期一

MySQL Index Building Tips

1. 資料種類較少 ex 男, 女 的index 在複合 index 中 放越前越好 (B-Tree divide)

2. 會按 index 建立的時間來吃, 吃到就不會繼續往下找,即使有更好的index~~

3. where date_format('A') = '20080723'
mod('A') = 5
=> 在設計之初 , 就要規劃好 避免在where 中 轉 格式.

4. where A is NULL => 會 full table scan
可以放default , ex: '0' => where A = 0 or "NULL" => where A = 'NULL'

2008年6月2日 星期一

Oracle Text

Form http://www.oracle.com/technology/products/text/index.html
Oracle Text
Oracle Text uses standard SQL to index, search, and analyze text and documents stored in the Oracle database, in files, and on the web. Oracle Text can perform linguistic analysis on documents, as well as search text using a variety of strategies including keyword searching, context queries, Boolean operations, pattern matching, mixed thematic queries, HTML/XML section searching, and so on. It can render search results in various formats including unformatted text, HTML with term highlighting, and original document format. Oracle Text supports multiple languages and uses advanced relevance-ranking technology to improve search quality. Oracle Text also offers advanced features like classification, clustering, and support for information visualization metaphors.

Oracle TimesTen In-Memory Database

http://www.oracle.com/timesten/index.html

Database Built in Memory : Oracle TimesTen

2008年5月27日 星期二

Select * From ap2_class_mapping Where class_id in ('0002','0012')
=> 會吃 index
Select * From ap2_class_mapping Where class_id in (0002,0012)
=> Full Scan

=> 有沒有單引號差很多

2008年5月17日 星期六

From ITHome
MySQL漸有大型企業採用,取得認證就業機會高
文/黃彥棻 (記者) 2008-02-01

MySQL在推出5.0版本時,將證照名稱正名,可以從證照看出是資料庫開發或者是資料庫管理員,目前臺灣若要考CMDEV和CMDBA,可以到全省VUE考試中心線上報名及考試。

由開放原始碼撰寫的資料庫產品MySQL,日前雖然被昇陽(Sun)併購,但因為MySQL有免費版和商業版,成為臺灣中小企業和個人用戶使用頻率最高的資料庫產品。但近年有不少大型企業開始評估或已經使用MySQL後,也使得取得MySQL證照的IT人,工作機會水漲船高。

MySQL資料庫因為是開放源碼撰寫的產品,對於許多SOHO或者是中小企業主而言,免費又兼具效能的MySQL,往往是第一也是唯一的資料庫選擇。巨匠電腦PHP與MySQL課程講師梁國亮表示,近來也發現有一些系統廠商或者是中小企業主,將MySQL作為單純進銷存系統或者是ERP(企業資源規畫)的後端資料庫使用。此外,也發現有一些中大型的網站或者是公家機關,也開始使用MySQL,「使用對象不再侷限以往的中小企業或者是SOHO族。」梁國亮說。

不只如此,梁國亮也觀察到,許多重量級廠商已經在部分的產品線上使用MySQL,例如電信業者彙整繳費資料到前端資料庫,就是使用MySQL;搜尋引擎業者某一些前端的資料庫,或者是某些大型的電子商務網站,甚至是美國最著名的網路書店Amazon,都有部分使用MySQL資料庫。

除了這些大型企業也開始使用MySQL資料庫外,梁國亮自身的教學經驗中也發現,有某家DRAM廠商,正在積極評估是否可以部分採用較為便宜的 MySQL資料庫,作為生產數據分析之用。他進一步表示,這家企業主對於MySQL的課程,要求到非常進階的使用功能,對於效能的調校與掌握,也要求務必徹底了解。梁國亮表示,這間DRAM業者為了降低成本,開始評估採用MySQL資料庫的可能性,如果效能上能夠符合該業者的需求,「光是1年資料庫軟體的授權費用,就可以節省上千萬元,」梁國亮說。

目前MySQL有3張相關證照,分別是基礎開發的CMDEV(Certified MySQL Developer)、資料庫管理員的CMDBA(Certified MySQL DBA)和高階叢集運算的CMCDBA(Certified MySQL Cluster DBA)。梁國亮目前已經取得CMDEV和CMDBA兩張證照,而CMCDBA則是去年下半年才推出的新證照。

梁國亮指出,目前證照的名稱是去年底MySQL升級到5.0版後,才重新命名的,原本在MySQL 4.0版本中,分成Core和Profession的兩張證照,難以從證照名稱上就看出原來Core就是資料庫開發工程師,Profession就是資料庫管理員。所以在MySQL 5.0版本中,才從善如流,從證照名稱就可以看出特色。

CMDEV和CMDBA都需要考2科上機的實機考試,單選題和複選題都有。梁國亮經驗表示,在考取CMDEV證照時,因為偏重開發的功能,「考生對於SQL的語法必須非常的了解,」梁國亮依自己考試經驗表示,考題上常出現考你一串語法後,問考生之後的執行結果為何,「這必須對於SQL語法非常熟悉。」他說。

至於CMDBA的考試上,梁國亮表示,主要是考驗考生對資料庫管理的概念和相關程序的了解,不論是使用者、權限管理,資料庫維護,包含備份、還原、目錄(Index)或重整等,都必須相當熟悉。他說,因為考試重視程序,考題就會有類似「資料庫壞了,正確的挽救程序應該如何執行?」的題目。

梁國亮表示,對於一個資料庫管理員而言,MySQL只是其中的一個產品類型,下一步發展的方向,不論是微軟的SQL Server 2005或者是大型的商用資料庫軟體如甲骨文或SAP等,都是進階學習的選擇。

目前臺灣若要考CMDEV和CMDBA,可以到全省VUE考試中心線上報名及考試。文⊙黃彥棻
from http://blog.pixnet.net/miles0722/post/8396830
MySQL截至目前為止有四種認證:

Certified MySQL Associate (CMA): MySQL for Beginners
Certified MySQL 5.0 Developer (CMDEV): MySQL 5.0 for Developers
Certified MySQL 5.0 Database Administrator (CMDBA): MySQL 5.0 for DBAs
Certified MySQL 5.1 Cluster Database Administrator (CMCDBA): MySQL Cluster for High Availability

其中 CMA只需通過一科,而CMEDV與CMDBA皆需通過兩科,CMCDBA則需先有CMDBA認證,加上通過一科才能擁有。

每次考試皆是US$200。

Exam Exam Code Questions Passing Score Exam time CMA

010-* 50 36-38 60 minutes Developer-I

003-* 70 42-44 90 minutes Developer-II

004-* 70 42-44 90 minutes DBA-I

005-* 70 44-46 90 minutes DBA-II

006-* 70 44-46 90 minutes Cluster DBA

009-* 70 42-44 90 minutes Core to Developer upgr.

007-* 60 34-36 75 minutes Professional to DBA upgr.

008-* 60 34-36 75 minutes

除了CMCDBA,其他三個認證可以買 MySQL 5.0 Certification Study Guide 自修,天瓏書局可以買得到。此書依據Developer-I、Developer-II、DBA-I與DBA-II分為四大部份四十二章。若是要考CMA,依據官方網站的說明,則需選讀此書的
Chapter 1: Sections 1.1 and 1.2
Chapter 5: Sections 5.1 through 5.4, 5.5 (but not 5.5.2 and 5.5.3), 5.6 and 5.7
Chapter 7: All
Chapter 8: All
Chapter 9: All, except for 9.6
Chapter 10: 10.5
Chapter 11: All
Chapter 14: Sections 14.1, 14.2 (but not 14.2.1 through 14.2.3), 14.3, 14.4, 14.6
Chapter 15: All, except 15.2.3 and 15.3.1
Chapter 29: Parts 29.4.2 and 29.4.3
Chapter 32: Section 32.4
網站上建議下列章節也要讀
Chapter 2 : All
Chapter 5: parts 5.4.1, 5.4.3
Chapter 20: 20.3
Chapter 25: 25.5, 25.6
Chapter 29: 29.4.6
Chapter 31: All



若是要考CMCDBA,則是要買 MySQL Cluster Certification Study Guide 一書。

附帶一提的是,MySQL 5.0 Certification Study Guide的後面書皮內側有一組號碼,第一次考試使用可以打75折,還不錯說~~不過可是有期限的哦,在最下面一行有寫,小小的字。

點這可以看到世界上有多少人拿到MySQL認證。

MySQL官方網站

2008年5月15日 星期四

from
http://www.itpub.net/114023.html
bitmap 的一点探究

1:bitmap 索引是分段存储的,也就是说很多条记录可能是分做了N段来存储,也就是有N个begin/end ,当新的记录 insert 而使用以前未曾使用过的物理地址的时候,会产生一个bitmap 段来存储,就算只有一条记录

2: 当删除一条记录的时候,在bitmap 索引上做了一个delete 的标记并用一新的记录来标记了,下面请看具体的演示

3: 当 dml发生的时候,会lock住某个值的存储bit的那一rowid所在的记录,参考下面的 row 中 lock ,这样显然会影响并发


SQL> create table tn(a number, b number);

Table created.

SQL> insert into tn select rownum,mod(rownum,5) from all_objects where rownum < 21;

20 rows created.

SQL> commit;

Commit complete.

SQL> create bitmap index tn_bitmap on tn(b);

Index created.

SQL> exec show_space('tn_bitmap',user,'INDEX');
Free Blocks.............................0
Total Blocks............................16
Total Bytes.............................131072
Unused Blocks...........................14
Unused Bytes............................114688
Last Used Ext FileId....................3
Last Used Ext BlockId...................1954
Last Used Block.........................2

PL/SQL procedure successfully completed.

SQL> select * from tn;

A B
---------- ----------
1 1
2 2
3 3
4 4
5 0
6 1
7 2
8 3
9 4
10 0
11 1

A B
---------- ----------
12 2
13 3
14 4
15 0
16 1
17 2
18 3
19 4
20 0

20 rows selected.

SQL> alter system dump datafile 3 block 1955;

System altered.

Block header dump: 0x00c007a3
Object id on Block? Y
seg/obj: 0x66da csc: 0x00.18a0d77 itc: 2 flg: - typ: 2 - INDEX
fsl: 0 fnx: 0x0 ver: 0x01

Itl Xid Uba Flag Lck Scn/Fsc
0x01 xid: 0x0000.000.00000000 uba: 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
0x02 xid: 0x0002.040.000000ea uba: 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000

Leaf block dump
===============
header address 125987932=0x7826c5c
kdxcolev 0
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 4
kdxcosdc 0
kdxconro 5
kdxcofbo 46=0x2e
kdxcofeo 7918=0x1eee
kdxcoavs 7872
kdxlespl 0
kdxlende 0
kdxlenxt 0=0x0
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 8036
row#0[8013] flag: -----, lock: 0
col 0; len 1; (1): 80 ---表示值为0
col 1; len 6; (6): 00 c0 7e 03 00 00 ---rowid 起点的block和行号
col 2; len 6; (6): 00 c0 7e 03 00 17 ---rowid 结束的block和行号,注意17 = 16+7 = 23 ,也就是下面转换后的有效位置截止到23bit
col 3; len 4; (4): ca 10 42 08 ---把该值按照16进制数转化为 11001010 (首字节不表示rowid信息) 00010000 01000010 00001000 ,
凡是从起点到结束点内的1表示该值存在,这里有 一个必须要注意的问题是,这样转化后的位置并不是真实的物理位置,在每个字节内部bit还要颠倒一下顺序,首字节不表示位置信息
也就是说上面的应该转换为 00001000 01000010 00010000 ,发现正好每5个存在一个值为0的记录
row#1[7990] flag: -----, lock: 0
col 0; len 2; (2): c1 02 ---表示值为1
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 0f ---注意这里是f,也就是一共只有16位,因为1是第一条记录开始的,在16的位置就已经有5条了
col 3; len 3; (3): c9 21 84 注意这里的 21 84 正好16位,根据上面描述的规则转换后就是 10000100 00100001,4个1正好表示记录
row#2[7966] flag: -----, lock: 0
col 0; len 2; (2): c1 03 ---表示值为2
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 17
col 3; len 4; (4): ca 42 08 01
row#3[7942] flag: -----, lock: 0
col 0; len 2; (2): c1 04 ---表示值为3
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 17
col 3; len 4; (4): ca 84 10 02
row#4[7918] flag: -----, lock: 0
col 0; len 2; (2): c1 05 ---表示值为4
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 17
col 3; len 4; (4): ca 08 21 04
----- end of leaf block dump -----
End dump data blocks tsn: 2 file#: 3 minblk 1955 maxblk 1955



SQL> delete from tn where a = 2;

1 row deleted.

SQL> commit;

Commit complete.

SQL> alter system dump datafile 3 block 1955;

System altered.

SQL>

Block header dump: 0x00c007a3
Object id on Block? Y
seg/obj: 0x66da csc: 0x00.18a0d77 itc: 2 flg: - typ: 2 - INDEX
fsl: 0 fnx: 0x0 ver: 0x01

Itl Xid Uba Flag Lck Scn/Fsc
0x01 xid: 0x0000.000.00000000 uba: 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
0x02 xid: 0x0003.047.000000e9 uba: 0x00800dba.00d9.1f --U- 2 fsc 0x001a.018a0d7d

Leaf block dump
===============
header address 125987932=0x7826c5c
kdxcolev 0
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 4
kdxcosdc 0
kdxconro 6
kdxcofbo 48=0x30
kdxcofeo 7894=0x1ed6
kdxcoavs 7846
kdxlespl 0
kdxlende 1
kdxlenxt 0=0x0
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 8036
row#0[8013] flag: -----, lock: 0
col 0; len 1; (1): 80
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 17
col 3; len 4; (4): ca 10 42 08
row#1[7990] flag: -----, lock: 0
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 0f
col 3; len 3; (3): c9 21 84
row#2[7894] flag: -----, lock: 2 ---这是删除后的拷贝,我们发现删除的时候该行已经加锁 lock : 2
col 0; len 2; (2): c1 03
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 17
col 3; len 4; (4): ca 40 08 01 ---我们发现 ca 42 已经变成 ca 40 ,也就是已经少掉一位bit了,正好是删除的那一条记录
row#3[7966] flag: ---D-, lock: 2 ---这里我们发现值为2的记录已经有删除过的 ---D- ,D表示delete
col 0; len 2; (2): c1 03
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 17
col 3; len 4; (4): ca 42 08 01
row#4[7942] flag: -----, lock: 0
col 0; len 2; (2): c1 04
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 17
col 3; len 4; (4): ca 84 10 02
row#5[7918] flag: -----, lock: 0
col 0; len 2; (2): c1 05
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 17
col 3; len 4; (4): ca 08 21 04
----- end of leaf block dump -----
End dump data blocks tsn: 2 file#: 3 minblk 1955 maxblk 1955
再继续补充

首先truncate 表所有数据
truncate table tn;

SQL> exec show_space('tn_bitmap','i');
Free Blocks.............................0
Total Blocks............................16
Total Bytes.............................131072
Unused Blocks...........................14
Unused Bytes............................114688
Last Used Ext FileId....................3
Last Used Ext BlockId...................1954
Last Used Block.........................2

PL/SQL procedure successfully completed.

可以看出索引是空的

然后插入一条数据

SQL> insert into tn values(1,1);

1 row created.

SQL> commit;

Commit complete.

SQL> alter system dump datafile 3 block 1955;

System altered.



row#0[8009] flag: -----, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 07
col 3; len 1; (1): 00
row#1[8030] flag: ---D-, lock: 2
col 0; NULL
col 1; NULL
col 2; NULL
col 3; NULL




SQL> insert into tn values(1,1);

1 row created.

SQL> commit;

Commit complete.

SQL> alter system dump datafile 3 block 1955;

System altered.



row#0[8009] flag: ---D-, lock: 2 -- 标记删除,下面一份是拷贝
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 07
col 3; len 1; (1): 00
row#1[7987] flag: -----, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 c0 7e 03 00 00 00---07 正好表示8 rows
col 2; len 6; (6): 00 c0 7e 03 00 07
col 3; len 2; (2): c8 03 -- 03 正好表示2条记录被插入



SQL> insert into tn values(1,1);

1 row created.

SQL> alter system dump datafile 3 block 1955;

System altered.

row#0[7987] flag: ---D-, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 07
col 3; len 2; (2): c8 03
row#1[7965] flag: -----, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 07
col 3; len 2; (2): c8 07 -- 07 正好表示3条记录被插入



SQL> insert into tn values(1,1);

1 row created.

SQL> insert into tn values(1,1);

1 row created.

SQL> insert into tn values(1,1);

1 row created.

SQL> insert into tn values(1,1);

1 row created.

SQL> insert into tn values(1,1);

1 row created.

SQL> commit;

Commit complete.

SQL> alter system dump datafile 3 block 1955;

System altered.

我们在同一个session中同一个事务连续插入5条记录,发现在bitmap中居然做了5个拷贝

row#0[7987] flag: ---D-, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 07
col 3; len 2; (2): c8 03
row#1[7965] flag: ---D-, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 07
col 3; len 2; (2): c8 07
row#2[7943] flag: ---D-, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 07
col 3; len 2; (2): c8 0f
row#3[7921] flag: ---D-, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 07
col 3; len 2; (2): c8 1f
row#4[7899] flag: ---D-, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 07
col 3; len 2; (2): c8 3f
row#5[7877] flag: ---D-, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 07
col 3; len 2; (2): c8 7f
row#6[7855] flag: -----, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 07
col 3; len 2; (2): c8 ff -- ff 正好表示8条记录被插入


SQL> insert into tn values(1,1);

1 row created.

SQL> commit;

Commit complete.

SQL> alter system dump datafile 3 block 1955;

System altered.

SQL>

-- 上一个bitmap段存储表示8条记录,我们再插入第9条记录再来看

row#0[7855] flag: -----, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 c0 7e 03 00 00
col 2; len 6; (6): 00 c0 7e 03 00 07
col 3; len 2; (2): c8 ff -- 8条记录已满,也把前面的前8条的多拷贝给清除掉了
row#1[7834] flag: -----, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 c0 7e 03 00 08
col 2; len 6; (6): 00 c0 7e 03 00 0f
col 3; len 1; (1): 00 新插入的第9条记录被新的从 08 -- 0f 这8个字节用来存储


综合上面的实验可以看出,当单条insert发生的时候,会以8条记录为一个bitmap row 来存储,这正好是一个字节的bit,并且就算是
相同事务中的insert也会导致大量的拷贝和lock产生,严重影响性能,甚至可能发生行迁移等严重问题,所以在经常发生变化的表中
我们不应该采用 bitmap index ,当发生update 的时候情形更为复杂,暂时不予讨论了
///////////////
SQL> truncate table tn;

表已截掉。

SQL> exec show_space('tn_bitmap',user,'INDEX');
Free Blocks.............................0
Total Blocks............................3
Total Bytes.............................12288
Unused Blocks...........................1
Unused Bytes............................4096
Last Used Ext FileId....................1
Last Used Ext BlockId...................26474
Last Used Block.........................2

PL/SQL 过程已成功完成。

SQL> alter system dump datafile 1 block 26475;

系统已更改。

Leaf block dump
===============
header address 83060828=0x4f3685c
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 4
kdxcosdc 0
kdxconro 0
kdxcofbo 36=0x24
kdxcofeo 3940=0xf64
kdxcoavs 3904
kdxlespl 0
kdxlende 0
kdxlenxt 0=0x0
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 3940
----- end of leaf block dump -----
End dump data blocks tsn: 0 file#: 1 minblk 26475 maxblk 26475
索引已经清空

SQL> insert into tn values (1, 1);

已创建 1 行。

SQL> /

已创建 1 行。

SQL> /

已创建 1 行。

SQL> /

已创建 1 行。

SQL> /

已创建 1 行。

SQL> /

已创建 1 行。

SQL> /

已创建 1 行。

SQL> /

已创建 1 行。

SQL> /

已创建 1 行。

SQL> /

已创建 1 行。

依次插入10行数据。

SQL> commit;

提交完成。

SQL> alter system dump datafile 1 block 26475;

系统已更改。

Leaf block dump
===============
header address 83060828=0x4f3685c
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 4
kdxcosdc 0
kdxconro 11
kdxcofbo 58=0x3a
kdxcofeo 3716=0xe84
kdxcoavs 3658
kdxlespl 0
kdxlende 9
kdxlenxt 0=0x0
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 3940
row#0[3913] flag: ---D-, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 40 67 68 00 00
col 2; len 6; (6): 00 40 67 68 00 07
col 3; len 1; (1): 00
row#1[3891] flag: ---D-, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 40 67 68 00 00
col 2; len 6; (6): 00 40 67 68 00 07
col 3; len 2; (2): c8 03
row#2[3869] flag: ---D-, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 40 67 68 00 00
col 2; len 6; (6): 00 40 67 68 00 07
col 3; len 2; (2): c8 07
row#3[3847] flag: ---D-, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 40 67 68 00 00
col 2; len 6; (6): 00 40 67 68 00 07
col 3; len 2; (2): c8 0f
row#4[3825] flag: ---D-, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 40 67 68 00 00
col 2; len 6; (6): 00 40 67 68 00 07
col 3; len 2; (2): c8 1f
row#5[3803] flag: ---D-, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 40 67 68 00 00
col 2; len 6; (6): 00 40 67 68 00 07
col 3; len 2; (2): c8 3f
row#6[3781] flag: ---D-, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 40 67 68 00 00
col 2; len 6; (6): 00 40 67 68 00 07
col 3; len 2; (2): c8 7f
row#7[3759] flag: -----, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 40 67 68 00 00
col 2; len 6; (6): 00 40 67 68 00 07
col 3; len 2; (2): c8 ff
row#8[3738] flag: ---D-, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 40 67 68 00 08
col 2; len 6; (6): 00 40 67 68 00 0f
col 3; len 1; (1): 00
row#9[3716] flag: -----, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 40 67 68 00 08
col 2; len 6; (6): 00 40 67 68 00 0f
col 3; len 2; (2): c8 03
row#10[3934] flag: ---D-, lock: 2
col 0; NULL
col 1; NULL
col 2; NULL
col 3; NULL
----- end of leaf block dump -----
End dump data blocks tsn: 0 file#: 1 minblk 26475 maxblk 26475

oracle对每次插入的数据都进行索引。


SQL> truncate table tn;

表已截掉。

SQL> alter system dump datafile 1 block 26475;

系统已更改。

Leaf block dump
===============
header address 83060828=0x4f3685c
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 4
kdxcosdc 0
kdxconro 0
kdxcofbo 36=0x24
kdxcofeo 3940=0xf64
kdxcoavs 3904
kdxlespl 0
kdxlende 0
kdxlenxt 0=0x0
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 3940
----- end of leaf block dump -----

一次性插入10条数据
SQL> insert into tn select 1,1 from user_objects where rownum < 11;

已创建10行。

SQL> commit;

提交完成。

SQL> alter system dump datafile 1 block 26475;

系统已更改。

Leaf block dump
===============
header address 83060828=0x4f3685c
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 4
kdxcosdc 0
kdxconro 2
kdxcofbo 40=0x28
kdxcofeo 3911=0xf47
kdxcoavs 3871
kdxlespl 0
kdxlende 1
kdxlenxt 0=0x0
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 3940
row#0[3911] flag: -----, lock: 2
col 0; len 2; (2): c1 02
col 1; len 6; (6): 00 40 67 68 00 00
col 2; len 6; (6): 00 40 67 68 00 0f
col 3; len 3; (3): c9 ff 03 一次性插入的数据,oracle会对整批数据进行bitmap索引。
row#1[3934] flag: ---D-, lock: 2
col 0; NULL
col 1; NULL
col 2; NULL
col 3; NULL
----- end of leaf block dump -----
End dump data blocks tsn: 0 file#: 1 minblk 26475 maxblk 26475

因此我认为对于包含bitmap索引的表应当减少对数据库操作的数量。运用批量入库的方法会使性能得到较大的提高。

有什么不对的地方还请指正。


my reply:

综合上面的实验可以看出,当单条insert发生的时候,会以8条记录为一个bitmap row 来存储,这正好是一个字节的bit,并且就算是
相同事务中的insert也会导致大量的拷贝和lock产生,严重影响性能,甚至可能发生行迁移等严重问题,所以在经常发生变化的表中
我们不应该采用 bitmap index ,当发生update 的时候情形更为复杂,暂时不予讨论了



结合
前面的第一条:
:bitmap 索引是分段存储的,也就是说很多条记录可能是分做了N段来存储,也就是有N个begin/end ,当新的记录 insert 而使用以前未曾使用过的物理地址的时候,会产生一个bitmap 段来存储,就算只有一条记录


所以我的实验中可能没有很好的做归纳,但是现象都是有的,描述的比较零散



就是说假如你们每天入库 1000万条记录
那创建 bitmap 索引的这个列有多少不同的值,如果有10万个不同的值以上,那采用 bitmap 是否合适就值得考虑了

2008年5月13日 星期二

Oracle Partion

form
http://jzhua.javaeye.com/blog/166078

一、Oracle分区简介
ORACLE的分区是一种处理超大型表、索引等的技术。分区是一种“分而治之”的技术,通过将大表和索引分成可以管理的小块,从而避免了对每个表作为一个大的、单独的对象进行管理,为大量数据提供了可伸缩的性能。分区通过将操作分配给更小的存储单元,减少了需要进行管理操作的时间,并通过增强的并行处理提高了性能,通过屏蔽故障数据的分区,还增加了可用性。
二、Oracle分区优缺点
 优点:
增强可用性:如果表的某个分区出现故障,表在其他分区的数据仍然可用;
维护方便:如果表的某个分区出现故障,需要修复数据,只修复该分区即可;
均衡I/O:可以把不同的分区映射到磁盘以平衡I/O,改善整个系统性能;
改善查询性能:对分区对象的查询可以仅搜索自己关心的分区,提高检索速度。
 缺点:
分区表相关:已经存在的表没有方法可以直接转化为分区表。不过 Oracle 提供了在线重定义表的功能。
三、Oracle分区方法
 范围分区:
范围分区就是对数据表中的某个值的范围进行分区,根据某个值的范围,决定将该数据存储在哪个分区上。如根据序号分区,根据业务记录的创建日期进行分区等。
 Hash分区(散列分区):
散列分区为通过指定分区编号来均匀分布数据的一种分区类型,因为通过在I/O设备上进行散列分区,使得这些分区大小一致。
 List分区(列表分区):
当你需要明确地控制如何将行映射到分区时,就使用列表分区方法。与范围分区和散列分区所不同,列表分区不支持多列分区。如果要将表按列分区,那么分区键就只能由表的一个单独的列组成,然而可以用范围分区或散列分区方法进行分区的所有的列,都可以用列表分区方法进行分区。
 范围-散列分区(复合分区):
有时候我们需要根据范围分区后,每个分区内的数据再散列地分布在几个表空间中,这样我们就要使用复合分区。复合分区是先使用范围分区,然后在每个分区内再使用散列分区的一种分区方法(注意:先一定要进行范围分区)
 范围-列表分区(复合分区):
范围和列表技术的组合,首先对表进行范围分区,然后用列表技术对每个范围分区再次分区。与组合范围-散列分区不同的是,每个子分区的所有内容表示数据的逻辑子集,由适当的范围和列表分区设置来描述。(注意:先一定要进行范围分区)

四、Oracle表分区表操作
--Partitioning 是否为true
select * from v$option s order by s.PARAMETER desc

--创建表空间
CREATE TABLESPACE "PARTION_03"
LOGGING
DATAFILE 'D:\ORACLE\ORADATA\JZHUA\PARTION_03.dbf' SIZE 50M
EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO

--删除表空间
drop tablespace partion_01


--范围 分区技术
create table Partition_Test
(
PID number not null,
PITEM varchar2(200),
PDATA date not null
)
partition by range(PID)
(
partition part_01 values less than(50000) tablespace dinya_space01,
partition part_02 values less than(100000) tablespace dinya_space02,
partition part_03 values less than(maxvalue) tablespace dinya_space03
)

create table Partition_TTest
(
PID number not null,
PITEM varchar2(200),
PDATA date not null
)
partition by range(PDATA)
(
partition part_t01 values less than(to_date('2004-01-01','yyyy-mm-dd')) tablespace dinya_space01,
partition part_t02 values less than(to_date('2008-01-01','yyyy-mm-dd')) tablespace dinya_space02,
partition part_t03 values less than(maxvalue) tablespace dinya_space03
)

insert into Partition_Test(PID,PITEM,PDATA) select h.id,h.userid,h.rectime from st_handle h

select * from Partition_Test partition(part_01) t where t.pid = '1961'

--hash 分区技术
create table Partition_HashTest
(
PID number not null,
PITEM varchar2(200),
PDATA date not null
)
partition by hash(PID)
(
partition part_h01 tablespace dinya_space01,
partition part_h02 tablespace dinya_space02,
partition part_h03 tablespace dinya_space03
)

insert into Partition_HashTest(PID,PITEM,PDATA) select h.id,h.userid,h.rectime from st_handle h

select * from Partition_HashTest partition(part_h03) t where t.pid = '1961'


--复合分区技术
create table Partition_FHTest
(
PID number not null,
PITEM varchar2(200),
PDATA date not null
)
partition by range(PDATA) subpartition by hash(PID) subpartitions 3 store in (dinya_space01,dinya_space02,dinya_space03)
(
partition part_fh01 values less than(to_date('2004-01-01','yyyy-mm-dd')) tablespace dinya_space01,
partition part_fh02 values less than(to_date('2008-01-01','yyyy-mm-dd')) tablespace dinya_space02,
partition part_fh03 values less than(maxvalue) tablespace dinya_space03
)

insert into Partition_FHTest(PID,PITEM,PDATA) select h.id,h.userid,h.rectime from st_handle h

select * from Partition_FHTest partition(part_fh02) t where t.pid = '1961'

select * from Partition_FHTest partition(part_fh03) t

--速度比较
select * from st_handle h where h.rectime > to_date('2008-01-01','yyyy-mm-dd');

select * from Partition_FHTest partition(part_fh03) t where t.pdata > to_date('2008-01-01','yyyy-mm-dd');


--分区表操作

--增加一个分区
alter table Partition_Test add partition part_05 values less than (10020) tablespace dinya_space03

--查询分区数据
select * from Partition_FHTest partition(part_fh02) t

--修改分区里的数据
update Partition_FHTest partition(part_fh02) t set t.PITEM = 'JZHUA' where t.pid = '1961'

--删除分区里的数据
delete from Partition_FHTest partition(part_fh02) t where t.pid = '1961'

--合并分区
create table Partition_HB
(
PID number not null,
PITEM varchar2(200),
PDATA date not null
)
partition by range(PID)
(
partition part_01 values less than(50000) tablespace dinya_space01,
partition part_02 values less than(100000) tablespace dinya_space02,
partition part_03 values less than(maxvalue) tablespace dinya_space03
)

insert into Partition_HB(PID,PITEM,PDATA) select h.id,h.userid,h.rectime from st_handle h

select * from Partition_HB partition(part_03) t where t.pid = '100001'

alter table Partition_HB merge partitions part_01,part_02 into partition part_02;

--拆分分区
-- spilt partition 分区名 at(这里是一个临界区,比如:50000就是说小于50000的放在part_01,而大于50000的放在part_02中)
alter table Partition_HB split Partition part_02 at (50000) into (Partition part_01 tablespace dinya_space01, Partition part_02 tablespace dinya_space02);

--更改分区名
alter table Partition_HB rename Partition part_01_test to part_02;
五、Oracle索引分区表操作
分区表和一般表一样可以建立索引,分区表可以创建局部索引和全局索引。当分区中出现许多事务并且要保证所有分区中的数据记录的唯一性时采用全局索引。全局索引建立时 global 子句允许指定索引的范围值,这个范围值为索引字段的范围值。其实理论上有3中分区索引。

 Global索引(全局索引):
对于 global 索引,可以选择是否分区,而且索引的分区可以不与表分区相对应。当对分区进行维护操作时,通常会导致全局索引的 Invalid,必须在执行完操作后 Rebuild。Oracle9i 提供了 Update Global Indexes 语句,可以在进行分区维护的同时重建全局索引。
1:索引信息的存放位置与父表的Partition(分区)信息完全不相干。甚至父表是不是分区表都无所谓的。

create index dinya_idx_t on dinya_test(item_id) global partition by range(item_id) (
partition idx_1 values less than (1000) tablespace dinya_space01,
partition idx_2 values less than (10000) tablespace dinya_space02,
partition idx_3 values less than (maxvalue) tablespace dinya_space03
);
2:但是在这种情况下,如果父表是分区表,要删除父表的一个分区都必须要更新Global Index ,否则索引信息不正确
ALTER TABLE TableName DROP PARTITION PartitionName Update Global Indexes

 Local索引(局部索引):

对于 local 索引,每一个表分区对应一个索引分区(就是说一个分区表一个字段只可以建一个局部索引),当表的分区发生变化时,索引的维护由 Oracle 自动进行;
1:索引信息的存放位置依赖于父表的Partition(分区)信息,换句话说创建这样的索引必须保证父表是Partition(分区),索引信息存放在父表的分区所在的表空间。
2:但是仅可以创建在父表为HashTable或者composite分区表的。
3:仅可以创建在父表为HashTable或者composite分区表的。并且指定的分区数目要与父表的分区数目要一致。

create index dinya_idx_t on dinya_test(item_id) local (
partition idx_1 tablespace dinya_space01,
partition idx_2 tablespace dinya_space02,
partition idx_3 tablespace dinya_space03
);

不指定索引分区名直接对整个表建立索引
create index dinya_idx_t on dinya_test(item_id);