仓酷云

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 872|回复: 7
打印 上一主题 下一主题

[学习教程] MSSQL网页设计利用索引的误区之四:空值对索引的影响...

[复制链接]
小女巫 该用户已被删除
跳转到指定楼层
楼主
发表于 2015-1-16 22:37:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
这类操作的执行过程是,1)按照新的表定义建立一个临时表tmpa,2)将原表数据拷贝到临时表,3)将原始表改名tmpb,4)将tmpa改名为原表名,5)将tmpb删除。索引利用索引的误区之四:空值对索引的影响
我们起首做一些测试数据:

SQL>createtablet(xint,yint);



Tablecreated



请注重,这里我对表t做了一个独一(团结)索引:

SQL>createuniqueindext_idxont(x,y);



Indexcreated



SQL>insertintotvalues(1,1);



1rowinserted



SQL>insertintotvalues(1,NULL);



1rowinserted



SQL>insertintotvalues(NULL,1);



1rowinserted



SQL>insertintotvalues(NULL,NULL);



1rowinserted



SQL>commit;



Commitcomplete



上面我们剖析一下索引:

SQL>analyzeindext_idxvalidatestructure;



Indexanalyzed



SQL>selectname,lf_rowsfromindex_stats;



NAMELF_ROWS

----------------------------------------

T_IDX3



SQL>

然后,我们就能够看到,以后的索引中仅仅保留了3行数据。

请注重,下面我们拔出并提交了四行数据。

以是,这里就有一个结论:

Oracle的索引不保留全体为空的行。





我们持续拔出数据,如今再拔出几行全体为空的行:

SQL>insertintotvalues(NULL,NULL);



1rowinserted



SQL>insertintotvalues(NULL,NULL);



1rowinserted

我们看到如许的拔出,竟然没有违背后面我们设定的独一束缚(uniqueont(x,y)),

以是,这里我们又得出一个结论:

Oracle以为NULLNULL,进而(NULL,NULL)(NULL,NULL)

换句话说,Oracle以为空值(NULL)不即是任何值,包含空值也不即是空值。



我们看到上面的拔出会违背独一束缚(DEMO.T_IDX),这个很好了解了,由于它不是全体为空的值,即它不是(NULL,NULL),只要全体为空的行才被以为是分歧的行:

SQL>insertintotvalues(1,null);



insertintotvalues(1,null)



ORA-00001:违背独一束缚前提(DEMO.T_IDX)



SQL>insertintotvalues(null,1);



insertintotvalues(null,1)



ORA-00001:违背独一束缚前提(DEMO.T_IDX)



SQL>



请看上面的例子:

SQL>selectx,y,count(*)fromtgroupbyx,y;



XYCOUNT(*)

-----------------------

3

11

11

111

Executedin0.03seconds



SQL>selectx,y,count(*)fromtwherexisnullandyisnullgroupbyx,y;



XYCOUNT(*)

---------------------

3



Executedin0.01seconds



SQL>

SQL>selectx,y,count(*)fromtgroupbyx,yhavingcount(*)>1;



XYCOUNT(*)

------------------------------------

3



Executedin0.02seconds

SQL>

能够瞥见,完整为空的行有三行,这里我们又能够得出一个结论:

oracle在groupby子句中以为完整为空的行是不异的行

换句话说,在groupby子句中,oracle以为(NULL,NULL)=(NULL,NULL)







上面的语句,利用了复合索引(x,y)的前导列,一般如许的查询是会利用索引的,我们看看上面的例子:

select*fromtwherexisnull;



PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

--------------------------------------------------------------------

|Id|Operation|Name|Rows|Bytes|Cost|

--------------------------------------------------------------------

|0|SELECTSTATEMENT|||||

|*1|TABLEACCESSFULL|T||||

--------------------------------------------------------------------

PredicateInformation(identifiedbyoperationid):

---------------------------------------------------

1-filter("T"."X"ISNULL)

Note:rulebasedoptimization



14rowsselected



Executedin0.06seconds



我们看到下面的查询并没有利用索引,那末对照一下不利用把持的情形:

对照一下上面的查询:

select*fromtwherex=1;



PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

--------------------------------------------------------------------

|Id|Operation|Name|Rows|Bytes|Cost|

--------------------------------------------------------------------

|0|SELECTSTATEMENT|||||

|*1|INDEXRANGESCAN|T_IDX||||

--------------------------------------------------------------------

PredicateInformation(identifiedbyoperationid):

---------------------------------------------------

1-access("T"."X"=1)

Note:rulebasedoptimization



14rowsselected



Executedin0.04seconds

这个查询(wherex=1)如我们所但愿的那样利用了t_idx(x,y)复合索引,这里我们能够得出一个结论:

在利用ISNULL和ISNOTNULL前提的时分,Oracle不利用索引(由于Oracle的索引不存储空值,具体请拜见后面的相干内容)



那末我们怎样利用空值的对照前提呢?

起首,只管不在前导列上利用空值,请看上面的例子:

select*fromtwherex=1andyisnull;



PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

--------------------------------------------------------------------

|Id|Operation|Name|Rows|Bytes|Cost|

--------------------------------------------------------------------

|0|SELECTSTATEMENT|||||

|*1|INDEXRANGESCAN|T_IDX||||

--------------------------------------------------------------------

PredicateInformation(identifiedbyoperationid):

---------------------------------------------------

1-access("T"."X"=1)

filter("T"."Y"ISNULL)

Note:rulebasedoptimization



15rowsselected



select*fromtwherexisnullandy=1;



PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

--------------------------------------------------------------------

|Id|Operation|Name|Rows|Bytes|Cost|

--------------------------------------------------------------------

|0|SELECTSTATEMENT|||||

|*1|TABLEACCESSFULL|T||||

--------------------------------------------------------------------

PredicateInformation(identifiedbyoperationid):

---------------------------------------------------

1-filter("T"."Y"=1AND"T"."X"ISNULL)

Note:rulebasedoptimization



14rowsselected



另有一个能够变通的办法,即我们在创立表的时分,为每一个列都指定为非空束缚(NOTNULL),而且在需要的列上利用default值,如:

SQL>createtablelunar(

2c1varchar2(10)defaultempty

3constraintc1_notnullnotnull,

4c2number(10)default0

5constraintc2_notnullnotnull,

6c3datedefaultto_date(20990101,yyyymmdd)

7constraintc3_notnullnotnull);



表已创立。



已用工夫:00:00:00.00

SQL>insertintolunar(c1)values(first);



已创立1行。



已用工夫:00:00:00.00

SQL>insertintolunar(c2)values(99);



已创立1行。



已用工夫:00:00:00.00

SQL>insertintolunar(c3)values(sysdate);



已创立1行。



已用工夫:00:00:00.00

SQL>insertintolunar(c1,c3)values(ok,sysdate);



已创立1行。



已用工夫:00:00:00.00

SQL>insertintolunar(c2,c1)values(999,hello);



已创立1行。



已用工夫:00:00:00.00

SQL>commit;



提交完成。



已用工夫:00:00:00.00

SQL>select*fromlunar;



C1C2C3

------------------------------

first001-1月-99

empty9901-1月-99

empty019-10月-04

ok019-10月-04

hello99901-1月-99



已用工夫:00:00:00.00

SQL>selectc1,c2,to_char(c3,yyyy-mm-yy)fromlunar;



C1C2TO_CHAR(C3

------------------------------

first02099-01-99

empty992099-01-99

empty02004-10-04

ok02004-10-04

hello9992099-01-99



已用工夫:00:00:00.00

SQL>

然后我们再像利用一样平常的列那样,利用他们,而且公道的为他们创建索引信任就能够很好的进步使用的查询效力。
在需要把许多新记录插入某个数据表的场合,DELAY_KEY_WRITE选项的作用将非常明显。另外,索引还会在硬盘上占用相当大的空间。因此应该只为最经常查询和最经常排序的数据列建立索引。注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。
分手快乐 该用户已被删除
沙发
发表于 2015-1-19 19:13:49 来自手机 | 只看该作者
个人感觉没有case直观。而且默认的第三字段(还可能更多)作为groupby字段很容易造成新手的错误。
因胸联盟 该用户已被删除
板凳
发表于 2015-1-25 22:41:06 | 只看该作者
这是一个不错的新特性。虽然索引的附加字段没有索引键值效率高,但是相对映射到数据表中效率还是提高了很多。我做过试验,在我的实验环境中会比映射到表中提高30%左右的效率。
再见西城 该用户已被删除
地板
发表于 2015-2-4 10:46:03 | 只看该作者
而写到本地,我又考虑到效率问题.大家来讨论讨论吧,分数不打紧,就给10分,十全十美,没啥对错,各抒己见,但是要有说服力的哦~
海妖 该用户已被删除
5#
发表于 2015-2-9 22:15:09 | 只看该作者
相信各位对数据库和怎么样学习数据库都有一些经验和看法,也会有人走了一些弯路总结出自己的经验来,希望大家能把各自的看法和经验拿出来分享,给别人一份帮助,给自己一份快乐
6#
发表于 2015-2-28 00:20:18 | 只看该作者
如果处理少量数据,比如几百条记录的数据,我不知道这两种情况哪个效率更高,如果处理大量数据呢?比如有表中有20万条记录.
精灵巫婆 该用户已被删除
7#
发表于 2015-3-9 16:58:49 | 只看该作者
如果,某一版本可以提供强大的并发响应,但是没有Oracle的相应版本稳定,或者价格较贵,那么,它就是不适合的。
金色的骷髅 该用户已被删除
8#
发表于 2015-3-17 00:10:16 | 只看该作者
以前的DTS轻盈简单。但是现在的SSIS虽然功能强大了很多,但是总是让人感觉太麻烦。看看论坛中询问SSIS的贴子就知道。做的功能太强大了,往往会有很多用户不会用了
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|仓酷云 鄂ICP备14007578号-2

GMT+8, 2024-5-21 07:19

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表