123
返回列表 发新帖
楼主: xiaodong_1567

我有这样一个索引,什么时候会用上呢

[复制链接]
论坛徽章:
122
现任管理团队成员
日期:2011-05-07 01:45:08
21#
发表于 2008-4-14 18:10 | 只看该作者
找到了是ask tom上的~

n 长慢慢看看吧,最后提到了这个方法
You Asked

Hi, Tom,
I have a table
create table project (project_ID number primary key,
                teamid number,
                job varchar2(100),
                status number(1));

status=1 means it is an active project, otherwise it is archived,
I was told to enforce a unique rule: the job has to be unique in the same teamid
for the active projects, it means teamid and job have to be unique while
status=1, what is the best way to do this?

What happens if the job can be NULL?

Thanks


  
and we said...
Here is one method.  We can use a function based index on a function:

ops$tkyte@ORA8I.WORLD> create or replace function my_unique_function( p_teamid
in number, p_job in varchar2, p_status in number ) return varchar2
  2  DETERMINISTIC
  3  as
  4  begin
  5      if ( p_status = 1 )
  6      then
  7          return p_teamid || '/' || p_job;
  8      else
  9          return NULL;
10      end if;
11  end;
12  /

Function created.

Now, we have a function that if status = 1, it will return the TEAMID || '/'
|| JOB (if job is null-you'll get TEAMID || '/' and thats what will be uniqued).
If status is NULL or not equal to one, we return NULL.

This is nice since an index entry that is entirely NULL is not in the index (we
don't put fully null entries in our b*trees), we'll only actually index the data
we need to check

Now, we can create our table and index:

ops$tkyte@ORA8I.WORLD> create table project
  2  (project_ID number primary key,
  3   teamid number,
  4   job varchar2(100),
  5   status number(1)
  6  );
Table created.

ops$tkyte@ORA8I.WORLD> create unique index project_idx on project( substr(
my_unique_function(teamid,job,status), 1, 110 ) )
  2  /

Index created.

See



ops$tkyte@ORA8I.WORLD> insert into project values( 1, 10, 'a', 1 );
1 row created.

ops$tkyte@ORA8I.WORLD> insert into project values( 2, 10, 'a', 1 );
insert into project values( 2, 10, 'a', 1 )
*
ERROR at line 1:
ORA-00001: unique constraint (OPS$TKYTE.PROJECT_IDX) violated

that shows that we cannot insert the same TEAMID/JOB with a status of 1...
Lets see what happens when we update that status and try again:

ops$tkyte@ORA8I.WORLD> update project set status = 2 where project_id = 1 and
teamid = 10 and status = 1;

1 row updated.

ops$tkyte@ORA8I.WORLD> insert into project values( 2, 10, 'a', 1 );

1 row created.

as expected, it works... Now, lets put some more data in there:

ops$tkyte@ORA8I.WORLD> insert into project values( 3, 10, 'a', 2 );
1 row created.

ops$tkyte@ORA8I.WORLD> insert into project values( 4, 11, 'a', 1 );
1 row created.

ops$tkyte@ORA8I.WORLD> insert into project select rownum+50, 10, 'a', 2 from
all_users where rownum <= 100;

100 rows created.


ops$tkyte@ORA8I.WORLD> select count(*) from project;

  COUNT(*)
----------
       104

ops$tkyte@ORA8I.WORLD> select count(*) from project where status = 1;

  COUNT(*)
----------
         2
So, of 104 rows in the table, 2 have a status of 1.  Lets see what impact that
has on our index we are using:


ops$tkyte@ORA8I.WORLD> analyze index project_idx validate structure;
Index analyzed.

ops$tkyte@ORA8I.WORLD> select lf_rows from index_stats;

   LF_ROWS
----------
         2

Our index has but 2 entries -- only the rows that NEED to be validated will be
in our index.



Now, if you do not have the enterprise edition, you do not have function based
indexes.  In that case, the easiest thing for you to do would be to add another
column and a trigger to maintain it plus a unique constraint.

Here is an example of that:

we will use a table called project table

ops$tkyte@ORA8I.WORLD> create table project_TABLE
  2  (project_ID number primary key,
  3   teamid number,
  4   job varchar2(100),
  5   status number(1),
  6   extra number
  7  );

Table created.

That extra column will hold the primary key whenever status is NOT equal to 1,
that'll make it unique.  It'll be NULL otherwise.  We'll create a view that our
applications will use -- don't want them to see this extra column:

ops$tkyte@ORA8I.WORLD> create or replace view project
  2  as
  3  select project_id, teamid, job, status from project_table
  4  /

View created.

ops$tkyte@ORA8I.WORLD> create unique index project_idx on project_TABLE( teamid,
job, extra )
  2  /

Index created.

now, our unique index is on teamid, job, extra.  When status = 1, extra is
null so teamid, job must be unique.  Whan status is not 1, extra will be the
primary key and hence will be unique so that teamid/job don't have to be

ops$tkyte@ORA8I.WORLD> create or replace trigger project_trigger
  2  before insert or update of status on project_TABLE
  3  for each row
  4  begin
  5          if :new.status = 1
  6          then
  7                  :new.extra := null;
  8          else
  9                  :new.extra := :new.project_id;
10          end if;
11  end;
12  /

Trigger created.

that trigger does the work for us, making sure that extra is set properly.  If
you run the above example -- the results would be the same..http://asktom.oracle.com/~tkyte/article1/index.html
for why I used substr there and to discover more about function based indexes in
generalYou AskedMore on...unique condition on multiple columns  August 29, 2001 Reviewer:  Padders  from UK Tom - thanks for quick answer. I agree that PL/SQL function permits
more documentation. However this rather goes against your general
advice of language choice i.e. sql, plsql, java sp, c. In many cases
I suspect index naming convention would be sufficient to describe
its purpose.

I am now thinking that delimiter is a problem. If two jobs exists
with matching name except that one job has leading character which
happens to match delimiter then either version of index will not
permit combination. Perhaps it would be safer to use two column
version as in...

CREATE UNIQUE INDEX index_name ON table_name (
  DECODE (status, 1, teamid),
  DECODE (status, 1, job));

CREATE UNIQUE INDEX index_name ON table_name (
  CASE WHEN status = 1 THEN teamid END,
  CASE WHEN status = 1 THEN job END);
Followup: In hindsight I fully agree that the implementation of:

CREATE UNIQUE INDEX index_name ON table_name (
  DECODE (status, 1, teamid, NULL ),
  DECODE (status, 1, job, NULL ));

would be the best overall answer in terms of performance.

使用道具 举报

回复
论坛徽章:
273
生肖徽章2007版:猪
日期:2008-09-27 09:35:45明尼苏达森林狼
日期:2009-01-12 14:15:09生肖徽章2007版:猪
日期:2009-01-21 16:30:59布鲁克林篮网
日期:2009-03-03 14:42:32圣安东尼奥马刺
日期:2009-03-03 14:44:41生肖徽章2007版:鸡
日期:2009-03-03 21:45:52生肖徽章2007版:牛
日期:2009-03-09 14:03:42生肖徽章2007版:猪
日期:2009-03-10 21:37:00生肖徽章2007版:羊
日期:2009-03-16 10:17:11生肖徽章2007版:虎
日期:2009-03-24 21:26:52
22#
 楼主| 发表于 2008-4-14 20:13 | 只看该作者
原帖由 zergduan 于 2008-4-14 18:04 发表
我听说这种case语句建立索引是为了保证唯一性而不是用来使用的~
比如table A有3个字段 a , b, c
如果想保证a 为Null时 b唯一且 a not null时 c唯一,可以用case来建立唯一索引。
记得在某人的blog上看到过~


你给的例子看了,它是说那样能利用函数索引实现特定情况下的唯一,没说其它

使用道具 举报

回复
论坛徽章:
122
现任管理团队成员
日期:2011-05-07 01:45:08
23#
发表于 2008-4-14 20:19 | 只看该作者
原帖由 xiaodong_1567 于 2008-4-14 20:13 发表


你给的例子看了,它是说那样能利用函数索引实现特定情况下的唯一,没说其它

是呀,他只是说这种创建索引的方式,只是用来保证特殊的唯一性。

但是这个是函数索引,如果你想用到它就比必须使用函数作为条件。

并且你用case建立这样的函数索引,对于你说的应用没有任何意义呀~完全可以用普通的索引代替~

使用道具 举报

回复
论坛徽章:
273
生肖徽章2007版:猪
日期:2008-09-27 09:35:45明尼苏达森林狼
日期:2009-01-12 14:15:09生肖徽章2007版:猪
日期:2009-01-21 16:30:59布鲁克林篮网
日期:2009-03-03 14:42:32圣安东尼奥马刺
日期:2009-03-03 14:44:41生肖徽章2007版:鸡
日期:2009-03-03 21:45:52生肖徽章2007版:牛
日期:2009-03-09 14:03:42生肖徽章2007版:猪
日期:2009-03-10 21:37:00生肖徽章2007版:羊
日期:2009-03-16 10:17:11生肖徽章2007版:虎
日期:2009-03-24 21:26:52
24#
 楼主| 发表于 2008-4-14 20:29 | 只看该作者
原帖由 zergduan 于 2008-4-14 20:19 发表

是呀,他只是说这种创建索引的方式,只是用来保证特殊的唯一性。

但是这个是函数索引,如果你想用到它就比必须使用函数作为条件。

并且你用case建立这样的函数索引,对于你说的应用没有任何意义呀~完全可以用普通的索引代替~

我这个应该算部分数据索引
创建都能创建了,为什么不能使用呢

使用道具 举报

回复
论坛徽章:
122
现任管理团队成员
日期:2011-05-07 01:45:08
25#
发表于 2008-4-14 20:33 | 只看该作者
原帖由 xiaodong_1567 于 2008-4-14 20:29 发表

我这个应该算部分数据索引
创建都能创建了,为什么不能使用呢

你创建了一个函数索引,索引的键值中存储的是函数结果。
偏偏你的查询条件中没有相应的函数,你让我怎么可能用这个索引的~

使用道具 举报

回复
论坛徽章:
273
生肖徽章2007版:猪
日期:2008-09-27 09:35:45明尼苏达森林狼
日期:2009-01-12 14:15:09生肖徽章2007版:猪
日期:2009-01-21 16:30:59布鲁克林篮网
日期:2009-03-03 14:42:32圣安东尼奥马刺
日期:2009-03-03 14:44:41生肖徽章2007版:鸡
日期:2009-03-03 21:45:52生肖徽章2007版:牛
日期:2009-03-09 14:03:42生肖徽章2007版:猪
日期:2009-03-10 21:37:00生肖徽章2007版:羊
日期:2009-03-16 10:17:11生肖徽章2007版:虎
日期:2009-03-24 21:26:52
26#
 楼主| 发表于 2008-4-14 20:38 | 只看该作者
原帖由 zergduan 于 2008-4-14 20:33 发表

你创建了一个函数索引,索引的键值中存储的是函数结果。
偏偏你的查询条件中没有相应的函数,你让我怎么可能用这个索引的~

有点道理

使用道具 举报

回复
论坛徽章:
122
现任管理团队成员
日期:2011-05-07 01:45:08
27#
发表于 2008-4-14 20:49 | 只看该作者
晕,刚才看了一下书,你这个就使tom<Expert Oracle database architecture>中文章~你再好好看看书P466-P469,tom用case建立索引后是如何使用的~

使用道具 举报

回复
论坛徽章:
273
生肖徽章2007版:猪
日期:2008-09-27 09:35:45明尼苏达森林狼
日期:2009-01-12 14:15:09生肖徽章2007版:猪
日期:2009-01-21 16:30:59布鲁克林篮网
日期:2009-03-03 14:42:32圣安东尼奥马刺
日期:2009-03-03 14:44:41生肖徽章2007版:鸡
日期:2009-03-03 21:45:52生肖徽章2007版:牛
日期:2009-03-09 14:03:42生肖徽章2007版:猪
日期:2009-03-10 21:37:00生肖徽章2007版:羊
日期:2009-03-16 10:17:11生肖徽章2007版:虎
日期:2009-03-24 21:26:52
28#
 楼主| 发表于 2008-4-15 15:07 | 只看该作者
原帖由 zergduan 于 2008-4-14 20:49 发表
晕,刚才看了一下书,你这个就使tom中文章~你再好好看看书P466-P469,tom用case建立索引后是如何使用的~

where条件改成where  (case temporary when 'N' then 'N' end) = 'N';就行了

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表