在Oracle 10g,Number、Char和Varchar2类型作为主键,查询效率分析(一)

2014-11-24 12:34:55 · 作者: · 浏览: 0

背景
在实际项目中,设计 数据库表的主键生成机制有多种选择:Sequence、产品自增长、表自增长、UUID、复合主键。从主键单纯性和查询简单性考虑,首先不建议使用复合主键。从数据表重建和数据迁移的方便性考虑,首选UUID,但使用UUID就必须使用字符类型字段,有担心字符类型主键的查询效率远不及数字类型主键。另外,有观点指出,对Varchar2类型字段建立索引,查询时,不使用该索引。在网上搜索相关的文章后,没有可信证据,所以,自力更生,寻找验证方案。
www.2cto.com
方案设计
建三张相同结构的表,分别使用Number、Char和Varchar2类型作为主键(Number类型主键值用Sequence的方式生成,Char和Varchar2类型主键值用GUID类生成),此次仅测试数据库的性能,所以,一切操作仅使用SQL和PLSQL完成。执行以下操作,并记录执行时间:
1 每张表录入100万条记录。
2 按主键排序,抽取第50万个记录的主键,执行主键查询。
www.2cto.com
建表
-- Number类型主键
create table b2c_pk_number
(
id number(15),
name varchar2(32)
) tablespace ecsdata2;
alter table b2c_pk_number
add constraint pk_pk_number primary key (id)
using index tablespace ecsindex2;
-- Char类型主键
create table b2c_pk_char
(
id char(32),
name varchar2(32)
) tablespace ecsdata2;
alter table b2c_pk_char
add constraint pk_pk_char primary key (id)
using index tablespace ecsindex2;
-- Varchar2类型主键
create table b2c_pk_varchar2
(
id varchar2(32),
name varchar2(32)
) tablespace ecsdata2;
alter table b2c_pk_varchar2
add constraint pk_pk_varchar2 primary key (id)
using index tablespace ecsindex2;
插入100万条记录
-- Number类型主键
declare
v_total number := 1000000;
v_starttime timestamp;
v_endtime timestamp;
begin
v_starttime := systimestamp;
for idx in 1 .. v_total
loop
insert into b2c_pk_number(id,name) values(idx, sys_guid());

-- 每1万提交一次
if( mod(idx, 10000) = 0) then
-- dbms_output.put_line(idx);
commit;
end if;
end loop;

v_endtime := systimestamp;

dbms_output.put_line(v_endtime - v_starttime);
end;
-- Char类型主键
declare
v_total number := 1000000;
v_starttime timestamp;
v_endtime timestamp;
begin
v_starttime := systimestamp;
for idx in 1 .. v_total
loop
insert into b2c_pk_char(id,name) values(sys_guid(), sys_guid());

-- 每1万提交一次
if( mod(idx, 10000) = 0) then
-- dbms_output.put_line(idx);
commit;
end if;
end loop;

v_endtime := systimestamp;

dbms_output.put_line(v_endtime - v_starttime);
end;
-- Varchar2类型主键
declare
v_total number := 1000000;
v_starttime timestamp;
v_endtime timestamp;
begin
v_starttime := systimestamp;
for idx in 1 .. v_total
loop
insert into b2c_pk_varchar2(id,name) values(sys_guid(), sys_guid());

-- 每1万提交一次
if( mod(idx, 10000) = 0) then
-- dbms_output.put_line(idx);
commit;
end if;
end loop;

v_endtime := systimestamp;

dbms_output.put_line(v_endtime - v_starttime);
end;
结果

Number类型主键
Char类型主键
Varchar2类型主键
执行时间(单位:秒) 71.516642000 93.747191000 97.184995000
修正
考虑到,Number类型主键的新增记录少调用了一次sys_guid(),而且,在实际 系统中,会用到Sequence。所以,做出以下调整:
1 创建Sequence
create sequence seq_pk_number;
2 将b2c_pk_number表清空
truncate table b2c_pk_number;
3 修改新增记录的plsql,重新执行。
declare
v_total number := 1000000;
v_starttime timestamp;
v_endtime timestamp;
begin
v_starttime := systimestamp;
for idx in 1 .. v_total
loop
insert into b2c_pk_number(id,name) values(seq_pk_number.nextval, sys_guid());

-- 每1万提交一次
if( mod(idx, 10000) = 0) then
-- dbms_output.put_line(idx);
commit;
end if;
end loop;

v_endtime := systimestamp;

dbms_output.put_line(v_endtime - v_starttime);
end;
修正后结果
Number类型主键
Char类型主键
Varchar2