2009年2月6日星期五
Berkeley DB: C 语言访问从0开始 中文版 Chap1-4
本手册致力于提供对Berkeley DB函数库的一个介绍。实际上,它描述了如何创建一个非常简单的单线程的应用程序。而且不经意的是,本手册忽略了许多创建简单应用程序所不需要知道重要的DB的数据库引擎的特性。有一个特性是如此重要不可忽视,需要在此进行概要性的介绍: 环境.
虽然环境对于字节锱铢计较的嵌入式环境下的应用程序来说使用可能性极低,但是对于许多其他的应用程序来说并不在乎这么一点小事。环境从本质上来说,是一个或者多个数据库的封装。
打开一个环境之后,你将可以在那个环境之中打开数据库,数据库将因此相对于环境所配置的HOME目录来进行创建和定位。
环境提供了许多单独的数据库服务器所不能提供的特性:
* 多数据库文件
DB可以在磁盘上的一个物理文件中创建多个数据库。这种设计是为了能够使得应用程序能够打开少量的数据库。然而,为了能够使用该特性,你的应用程序必须使用环境文件。
* 多线程和多进程支持
在使用环境文件的时候, DB设置在内存中的缓冲和锁能够被所有在该环境文件中打开的数据库所共享。环境文件使你能够使用DB提供给多线程/进程访问DB数据库的子系统。例如,你可以使用一个环境文件来 使用 CDS (并发数据存储) , 锁子系统, 或者 共享内存缓冲池。
* 事务处理
DB 提供了事务子系统,为数据库写入提供了完整的ACID保护。(what is ACID-protection??) 在环境文件中设置使用事务子系统, 然后序列性的获取事务ID.
* 高可用性(复用)支持
DB 提供了一个复用子系统,使得单个的MASTER数据库能够复用多个只读的复用数据的拷贝。环境文件用于配置和管理这个子系统。
* 日志子系统
DB 为应用程序提供了预写式日志作为高度的灾难恢复对策。一旦激活了该功能,日志子系统允许应用程序通过日志文件中所包含的信息进行两种恢复(普通和catastrophic)
以上所有主题,都在 Berkeley DB Programmer's Reference Guide 中有描述。
2009年2月5日星期四
Berkeley DB: C 语言访问从0开始 中文版 Chap1-3
Berkeley DB提供了对所有数据管理的支持,包括位于内存中的非常小的数据库到巨大的拥有百万级记录和TB级数据的数据库。 DB的数据库能够保存最多256TB的数据。 单独一条记录的KEY或者DATA能偶保存最多4GB 数据。
DB的数据库将数据以二进制形式保存,可以跨平台使用,甚至无需考虑平台的处理器的字节序问题。有一点需要注意的是,在数据可移植性之外,在小端字节序的架构上,会遇到一些性能上的问题。 详细请参见 设置比较函数 以获得进一步的参考。
DB的数据库和数据能够支持并发访问 - 他们是线程安全的,并且他们在多进程的时候也能和平共处。
请注意, 为了能够使多线程可以共享数据库和缓冲,DB所采用的方法使得DB 不能够在 网络共享存储设备上(例如 NFS或者WINDOWS 网络共享)很好的使用。 因此,你不应将DB的数据库和环境放在通过网络共享方式挂接的驱动器上。
Berkeley DB: C 语言访问从0开始中文版 Chap1-1
在进一步深入之前,将向你描述一些你创建基于DB的应用程序的时候所会遇到的宏观性的概念。
抽象的说,DB数据库中包含着 记录 。 逻辑上,每一条记录标示一个数据库中的独立条目。每一个这样的记录包含两个部分的信息:键 和 数据. 本手册将偶尔使用 一条记录的键 或者 一条记录的数据,这样的名词在 处理一个或者多个数据库记录的语境中。
因为 DB数据库中使用了 key /Data 这样的对子,它们有时被认为是一个有两个子段的关系型数据库表。然而,data (有时是key, 依赖于DB所定义的存取方式) 能够保有非常复杂的数据。常见的伎俩是C语言的结构和其他的构造被存入记录中。这样有效的把一个 只有两个字段的表变为了一个n字段的表,其中n-1个字段是对应着数据结构的成员。
注意,DB数据库非常象一个关系型数据库中的一个表。许多DB应用程序因此需要使用多个DB数据库(就象关系型数据库里面有许多表一样)。
和关系型数据库系统不同的是,一个DB数据库仅仅包含有一个根据给定的存取方式(BTree, Queue, Hash )组织起来的记录集合。在关系型数据库系统中, 底层的存取方式往往被隐藏起来。
一般咸认,基于DB的应用程序应设计为,一个数据库存储一种特定类型的数据(就象在一个关系型数据库中, 一个单独的数据表保存了某种特定方面的数据)因为许多应用程序需要管理许多种数据,故而基于DB的应用程序经常使用到了多个DB数据库。
例如,一个会计应用程序。这种应用程序的数据管理涉及银行账户,记账账户,股票,借贷等等,同时还有客户,银行机构,客户账户等等。在传统的关系型数据库总,所有这些不同种类的信息将被用一系列复杂的数据表进行存储和管理。在基于DB的应用程序中,所有这些信息将被分割并用多个数据库进行存储和管理。
基于DB的应用程序能够通过一个可选的方法,数据库应用环境来更方便的使用多个数据库。更多信息请参考本手册的附录部分的 [[数据库应用环境]]。
利用大部分的DB的API时候,需要使用包含函数指针的特殊结构。这些回调函数称之为方法,因为它们看上去就想一个C++类中的方法,用于访问这些方法的变量,被称为句柄。就象使用一个数据库之前,需要先获得这个数据库的句柄。
从数据库获取数据有时被称为获取记录, 因为用于获取记录的方法叫做 get(). 同样,存入数据库记录被称为写入记录,因为你要调用put().
在使用数据库句柄向DB数据库存入记录的时候,记录将根据该DB数据库定义的排序方式存入。排序大部分都是根据key来进行的, 但是有时也考虑data . 如果存入一条记录,而该记录的key相同的记录已经存在于数据库中, 则新记录将替换老记录。然而,如果该数据库支持重复记录(具有相同的key 但是不同的数据),则新的记录将作为新记录作为重复记录登入数据库,且既存记录不会被覆盖。
如果一个DB数据库支持重复记录,那么你可以通过数据库句柄来仅仅获取重复记录集合中的第一条记录。
在使用数据库句柄时,可以通过一个特殊机制:游标来读写数据。游标是铁杆的迭代器,可以用来遍历数据库中的记录。翻来覆去,前前后后。也可以用游标来定位一条记录。在数据库支持重复记录的时候,游标是唯一的能够存取重复记录集合的方法。
最后,DB提供了一种特殊的数据库,称为第2梯队。
第2梯队为通常的数据库(称为第1梯队以区别于第2梯队)提供索引。第2梯队的数据库非常有趣,因为它们能够保存复杂的数据类型,但是查询到指定记录的话,仅仅需要该记录的key. 如果你希望能够通过某些惨不忍睹的零碎信息查询到一个记录,而且还不是key的话,你就需要用到第2梯队的数据库。
-----
专有名词翻译
secondary database 第2梯队
key 键盘
Berkeley DB: C getting started 从0 开始 Chap1-0
翻译 suning
工程开始日期 2009-02-04
原始版权声明
This documentation is distributed under the terms of the Sleepycat public license. You may review the terms of this license at: http://www.sleepycat.com/download/oslicense.html
Sleepycat Software, Berkeley DB, Berkeley DB XML and the Sleepycat logo are trademarks or service marks of Sleepycat Software, Inc. All rights to these marks are reserved. No third-party use is permitted without the express prior written consent of Sleepycat Software, Inc.
To obtain a copy of this document's original source code, please write to
11/9/2005
本翻译文稿声明
遵从创作共享协议。
目录
Chapter 1. Introduction to Berkeley DB 介绍
DB 是一个嵌入式的数据库引擎,所以她极端之迅速。你可以将她象其他的程序库一样编译并链接
进入你的程序。这就意味着DB运行在你的应用程序的进程空间中,可以避免访问单独的数据库服
务器时所发生的大量进程间通讯的成本。
作为一个进阶的性能提升手段,DB提供了一个内存中的缓冲来提高你经常使用的数据的访问速度。
一旦配置之后,这个缓冲的使用将对应用程序来说是透明的。她几乎不需要应用程序开发者来关
注她。
在其赤裸裸的高速度之外, DB的可配置性也有两把刷子。她提供了多种组织数据库中数据的方法。
被称为 存取方法,每一个这样的数据组织机制提供了非常不同的特性,以适应于不同的数据管理场
景。(注意,本手册将几乎完全着眼于 BTree 这种存取方式,因为这种方式为大量的数据库应用
程序所采用)
在此配置之上,DB提供了许多子系统,用于提高DB的兼容性。例如,许多应用程序要求写入保护,
用于提供数据的完整性保护,为此,DB能够启动一个事务子系统来对数据库写入提供事务性的访问。
如果要列出在哪些操作系统上可以使用DB, 实在是罄竹难书。笼统的说,它可以运行于所有主流
商业操作系统,包括许多嵌入式平台。
最后,DB还提供了丰富的应用程序接口。Sleepycat官方支持通过C,C++和JAVA的访问,但是还
有许多其他语言的访问DB的应用程序接口,例如脚本语言Perl和Python.
注意:
在你将要使用DB进行一些搞七捻三的活动之前,我要非常郑重的提示未成年人们:
DB不是一个关系型数据库(虽然你可以用她来创建一个关系型数据库)。我忠诚的
坦白,DB没有提供许多高级特性比如触发器, 也没有支持SQL。
DB仅仅使用有限的API集合即可有效的进行数据的存取活动。
关于这个手册
这个地方由于翻译者太懒,认为可以跳过,因此暂不翻译。
---------
专有名词
access method 存取方式
2009年2月4日星期三
Berkeley DB Related Links
http://www.oracle.com/technology/products/berkeley-db/index.html
Berkeley DB Online Manual
http://www.berkeleydb.net/man/bdb/index.html
Berkeley DB 的wikipedia 项目中提到了一本书
APress -The Berkeley DB book
该书有PDF版本,可以从如下链接访问
http://www.ebookee.com.cn/The-Berkeley-DB-Book_152798.html
2009年1月30日星期五
select into 和 insert into select 两种表复制语句
insert into destTbl(fld1, fld2) select fld1, 5 from srcTbl
以上两句都是将 srcTbl 的数据插入到 destTbl,但两句又有区别的:
* 第一句(select into from)要求目标表(destTbl)不存在,因为在插入时会自动创建。
* 第二句(insert into select from)要求目标表(destTbl)存在,由于目标表已经存在,所以我们除了插入源表(srcTbl)的字段外,还可以插入常量
2009年1月13日星期二
FWD: ORACLE中Like与Instr性能大比拼
作者:丹臣 | 【转载时请务必以超链接形式标明文章原始出处和作者信息及本声明】
地址:http://rdc.taobao.com/blog/dba/html/246_like_instr_performance.html
t表中将近有1100万数据,很多时候,我们要进行字符串匹配,在SQL语句中,我们通常使用like来达到我们搜索的目标。但经过实际测试发现,like的效率与instr函数差别相当大。下面是一些测试结果:
SQL> set timing on
SQL> select count(*) from t where instr(title,’手册’)>0;
COUNT(*)
———-
65881
Elapsed: 00:00:11.04
SQL> select count(*) from t where title like ‘%手册%’;
COUNT(*)
———-
65881
Elapsed: 00:00:31.47
SQL> select count(*) from t where instr(title,’手册’)=0;
COUNT(*)
———-
11554580
Elapsed: 00:00:11.31
SQL> select count(*) from t where title not like ‘%手册%’;
COUNT(*)
———-
11554580
另外,我在另外一个2亿多的表,使用8个并行,使用like查询很久都不出来结果,但使用instr,4分钟即完成查找,性能是相当的好。这些小技巧用好,工作效率提高不少。通过上面的测试说明,ORACLE内建的一些函数,是经过相当程度的优化的。
--EOF--
Trackback:http://rdc.taobao.com/blog/dba/html/246_like_instr_performance.html/trackback
2008年12月16日星期二
利用子查询更新字段
update sq_forum_reply s set floor = (
select row_number() over(partition by thread_id order by gmt_create)
from sq_forum_reply t
where s.id = t.id
and t.thread_id =20013990
and floor is null
) where thread_id=20013990 and floor is null;
查看执行计划发现,原因是子查询根据要更新的当前行的id去查询匹配记录,这样子查询每次只能查到一条记录,所以排序始终等于1。
修改语句后:
update sq_forum_reply s set floor = (
select rn from (
select id,row_number() over(partition by thread_id order by gmt_create) rn
from sq_forum_reply t
where t.thread_id = 20013990 and floor is null
) where s.id = id
) where thread_id=20013990 and floor is null ;
sql> select id,floor from sq_forum_reply where thread_id=20013990;
ID FLOOR
———- ———-
20004120 1
20004121 2
20004122 3
所以在写这类sql时,一定要确保子查询的结果集和要更新的结果集一致。
http://www.alidba.net/index.php/archives/50/trackback
2008年11月19日星期三
count(*)、count(1)、count(rowid)的对比
原文作者 bitirainy
http://bitirainy.itpub.net/post/330/1914
经常有人说count(1)比count(*)快。实际上是这样吗?不是的,作为数据库的衡量性能的逻辑读来说,是没有差异的。但是在实际的多次反复测试中,我们可以来对比看看真实状况。
SQL> create table t as select * from all_objects;
Table created.
SQL> select count(*) from all_objects;
COUNT(*)
----------
3789
SQL> desc t
Name Null? Type
----------------------------------------- -------- ----------------------------
OWNER NOT NULL VARCHAR2(30)
OBJECT_NAME NOT NULL VARCHAR2(30)
SUBOBJECT_NAME VARCHAR2(30)
OBJECT_ID NOT NULL NUMBER
DATA_OBJECT_ID NUMBER
OBJECT_TYPE VARCHAR2(18)
CREATED NOT NULL DATE
LAST_DDL_TIME NOT NULL DATE
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)
先 delete statistics , 各方式分别求 1000次 count
然后 analyze table ,各方式分别求 1000次 count
然后做个时间对比
服务器无外界干扰的情况下的反复测试的结果如下
declare
n_count number;
n_time0 number;
n_time1 number;
n_time2 number;
n_time3 number;
n_time4 number;
begin
execute immediate'analyze table t delete statistics';
select count(*) into n_count from t;
n_time0 := dbms_utility.get_time;
for i in 1..1000 loop
select /*+index(t t_index)*/ count(*) into n_count from t;
end loop;
n_time1 := dbms_utility.get_time;
for i in 1..1000 loop
select count(*) into n_count from t;
end loop;
n_time2 := dbms_utility.get_time;
for i in 1..1000 loop
select count(1) into n_count from t;
end loop;
n_time3 := dbms_utility.get_time;
for i in 1..1000 loop
select count(rowid) into n_count from t;
end loop;
n_time4 := dbms_utility.get_time;
dbms_output.put_line('the count of the table T : '||to_char(n_count));
dbms_output.put_line('before analyze ,loop 1000,/*+hints*/count(*) :'||to_char(n_time1 - n_time0 ));
dbms_output.put_line('before analyze ,loop 1000,count(*) :'||to_char(n_time2 - n_time1));
dbms_output.put_line('before analyze ,loop 1000,count(1) :'||to_char(n_time3 - n_time2));
dbms_output.put_line('before analyze ,loop 1000,count(rowid) :'||to_char(n_time4 - n_time3));
execute immediate'analyze table t compute statistics';
select count(*) into n_count from t;
n_time1 := dbms_utility.get_time;
for i in 1..1000 loop
select count(*) into n_count from t;
end loop;
n_time2 := dbms_utility.get_time;
for i in 1..1000 loop
select count(1) into n_count from t;
end loop;
n_time3 := dbms_utility.get_time;
for i in 1..1000 loop
select count(rowid) into n_count from t;
end loop;
n_time4 := dbms_utility.get_time;
dbms_output.put_line('the count of the table T : '||to_char(n_count));
dbms_output.put_line('after analyze ,loop 1000,count(*) :'||to_char(n_time2 - n_time1));
dbms_output.put_line('after analyze ,loop 1000,count(1) :'||to_char(n_time3 - n_time2));
dbms_output.put_line('after analyze ,loop 1000,count(rowid) :'||to_char(n_time4 - n_time3));
end;
the count of the table T : 3789
before analyze ,loop 1000,/*+hints*/count(*) :71
before analyze ,loop 1000,count(*) :63
before analyze ,loop 1000,count(1) :91
before analyze ,loop 1000,count(rowid) :88
the count of the table T : 3789
after analyze ,loop 1000,count(*) :28
after analyze ,loop 1000,count(1) :28
after analyze ,loop 1000,count(rowid) :79
PL/SQL procedure successfully completed.
SQL> /
the count of the table T : 3789
before analyze ,loop 1000,/*+hints*/count(*) :72
before analyze ,loop 1000,count(*) :61
before analyze ,loop 1000,count(1) :88
before analyze ,loop 1000,count(rowid) :85
the count of the table T : 3789
after analyze ,loop 1000,count(*) :28
after analyze ,loop 1000,count(1) :27
after analyze ,loop 1000,count(rowid) :82
PL/SQL procedure successfully completed.
从这里我们可以看出在时间的对比上,同样通过全表扫描和走索引,除了count(rowid)在走索引的时候明显慢外,其他情况下差异都不是很大,很明显,对于这样的求和来说,我们使用 count(*) 是没有什么不好的,count(1)更快纯粹是一个谬论。
更多的讨论可以参考
http://www.cnoug.org/viewthread.php?tid=857&highlight=count%2Bbiti_rainy
2008年11月9日星期日
2008年3月3日星期一
索引与Null值对于Hints及执行计划的影响
set autotrace=ON 失败的解决办法
由于B*Tree索引不存储Null值,所以在索引字段允许为空的情况下,某些Oracle查询不会使用索引.
很多时候,我们看似可以使用全索引扫描(Full Index Scan)的情况,可能Oracle就会因为Null值的存在而放弃索引.
在此情况下即使使用Hints,Oracle也不会使用索引,其根本原因就是因为Null值的存在.http://www.eygle.com/faq/AutoTrace.htm
2008年2月12日星期二
oracle索引的5种使用模式
索引的使用对数据库的性能有巨大的影响。
共有五类不同的使用模式。
1。INDEX UNIQUE SCAN 效率最高,主键或唯一索引
2。INDEX FULL SCAN 有顺序的输出,不能并行读索引
3。INDEX FAST FULL SCAN 读的最块,可以并行访问索引,但输出不按顺序
4。INDEX RANGE SCAN 给定的区间查询
5。INDEX SKIP SCAN 联合索引,不同值越少的列,越要放在前面
--实验后的总论。
能用唯一索引,一定用唯一索引
能加非空,就加非空约束
一定要统计表的信息,索引的信息,柱状图的信息。
联合索引的顺序不同,影响索引的选择,尽量将值少的放在前面
只有做到以上四点,数据库才会正确的选择执行计划。
conn system/manager
grant select any dictionary to scott;
conn scott/tiger
drop table t1 purge;
create table t1 as select * from dba_objects;
analyze table t1 compute statistics;
create index it1 on t1(object_type);
set autot traceonly
select distinct object_type from t1;
将是全表扫描,为什么不使用索引呢?因为索引中不能含有null值,
如果使用索引就可能产生不正确的结果。
--增加非空约束
alter table t1 modify (object_type not null);
select distinct object_type from t1 ;
使用INDEX FAST FULL SCAN方式查找数据
--
select object_type from t1;
使用INDEX FAST FULL SCAN,因为不需要排序
select object_type from t1 order by 1;
使用INDEX FULL SCAN,因为要按照顺序输出
select object_type from t1 where object_type='TABLE';
使用INDEX RANGE SCAN
--使用非唯一索引
create index i2t1 on t1(object_id);
select * from t1 where object_id=3762;
使用INDEX RANGE SCAN,因为数据库不知道是否唯一
--使用唯一索引
drop index i2t1;
create unique index i2t1 on t1(object_id);
使用INDEX UNIQUE SCAN,因为数据库知道是唯一的
--跳跃的扫描索引
create index i3t1 on t1(object_type,object_name);
select * from t1 where object_name='EMP';
select object_name from t1 where object_name='EMP';
使用INDEX SKIP SCAN,因为数据库知道可以跳过object_type,虽然object_name在第二个列。
--联合索引的顺序不同,影响索引的选择,尽量将值少的放在前面
drop index i3t1;
drop index it1;
create index i3t1 on t1(object_name,object_type);
select * from t1 where object_type='TABLE';
计划为全表扫描。