T1表 10000000万条数据,(插入时间36分钟,count(*)查询19秒,空间占用670M左右)
1.真正充分的利用索引比如like ‘张%‘ 就是符合SARG(符合扫描参数)标准而like ‘%张‘ 就不符合该标准
通配符%在字符串首字符的使用会导致索引无法使用,虽然实际应用中很难避免这样用,但还是应该对这种现象有所了解,至少知道此种用法性能是很低下的。
**********************************************
2.“非”操作符不满足SARG形式,使得索引无法使用不满足SARG形式的语句最典型的情况就是包括非操作符的语句,如:NOT、!=、<>、!<、!>、NOT EXISTS、NOT IN、NOT LIKE等。如果使用not 或者 <>,最好转换成别的方法,比如例子如下:
T1表 10000000万条数据,构建如下:(插入时间36分钟,count(*)查询19秒,空间占用670M左右)
DECLARE @i INTSET @i = 1WHILE @i<1000000BEGIN INSERT INTO t1 VALUES (‘zhang‘+CONVERT(char(50), @i),‘3.2‘,77); SET @i + 1;END
三种查询方式:
SELECT * FROM t1 WHERE id <>300000SELECT * FROM t1 WHERE id NOT IN (300000)SELECT * FROM t1 WHERE id >299999 AND id < 300001
在执行计划中可以明显看出,使用最后一种方式而不是前面两种方式进行查询。网上是这么说的,但自己做的试验100W条数据,开销计划是一样的。
*********************************************
3. 函数运算不满足SARG形式,使得索引无法使用例:下列SQL条件语句中的列都建有恰当的索引,但执行速度却非常慢:
select * from record where substring(card_no,1,4)=′5378′(13秒)select * from record where amount/30< 1000(11秒)select * from record where convert(char(10),date,112)=′19991201′(10秒)
分析:
where子句中对列的任何操作结果都是在SQL运行时逐列计算得到的,因此它不得不进行全表扫描,而没有使用该列上面的索引;如果这些结果在查询编译时就能得到,那么就可以被SQL优化器优化,使用索引,避免表搜索,因此将SQL重写成下面这样:
select * from record where card_no like ′5378%′(< 1秒)select * from record where amount < 1000*30(< 1秒)select * from record where date= ′1999/12/01′ (< 1秒)
你会发现SQL明显快很多
待测试.......
**********************************************
4.尽量不要对建立了索引的字段,作任何的直接处理
select * from employs where first_name + last_name =‘beill cliton‘;
无法使用索引,改为:
select * from employee wherefirst_name = substr(‘beill cliton‘,1,instr(‘beill cliton‘,‘ ‘)-1)andlast_name = substr(‘beill cliton‘,instr(‘beill cliton‘,‘ ‘)+1)
则可以使用索引
***********************************************
5.不同类型的索引效能是不一样的,应尽可能先使用效能高的比如:数字类型的索引查找效率高于字符串类型,定长字符串char,nchar的索引效率高于变长字符串varchar,nvarchar的索引。应该将where username=‘张三‘ and age>20改进为where age>20 and username=‘张三‘注意:此处,SQL的查询分析优化功能可以做到自动重排条件顺序,但还是建议预先手工排列好。
**************************************************
6.某些情况下IN 的作用与OR 相当 ,且都不能充分利用索引例:表stuff有200000行,id_no上有非群集索引,请看下面这个SQL:select count(*) from stuff where id_no in(′0′,′1′) (23秒)我 们期望它会根据每个or子句分别查找,再将结果相加,这样可以利用id_no上的索引;但实际上,它却采用了"OR策略",即先取出满足每个or子句的 行,存入临时数据库的工作表中,再建立唯一索引以去掉重复行,最后从这个临时表中计算结果。因此,实际过程没有利用id_no 上索引,并且完成时间还要 受tempdb数据库性能的影响。实践证明,表的行数越多,工作表的性能就越差,当stuff有620000行时,执行时间会非常长!如果确定不同的条件不会产生大量重复值,还不如将or子句分开:
select count(*) from stuff where id_no=′0′select count(*) from stuff where id_no=′1′
得到两个结果,再用union作一次加法合算。因为每句都使用了索引,执行时间会比较短,
select count(*) from stuff where id_no=′0′unionselect count(*) from stuff where id_no=′1′
从实践效果来看,使用union在通常情况下比用or的效率要高的多,而exist关键字和in关键字在用法上类似,性能上也类似,都会产生全表扫描,效率比较低下,根据未经验证的说法,exist可能比in要快些。
***************************************************
7.使用变通的方法提高查询效率
like关键字支持通配符匹配,但这种匹配特别耗时。例 如:select * from customer where zipcode like “21_ _ _”,即使在zipcode字段上已建立了索 引,在这种情况下也可能还是采用全表扫描方式。如果把语句改 为:select * from customer where zipcode >“21000”,在执行查询时就会利用索引,大大提高速度。但 这种变通是有限制的,不应引起业务意义上的损失,对于邮政编码而 言,zipcode like “21_ _ _” 和 zipcode >“21000” 意义是完全一致的。
*********************************************************人各有志,但富贵在天,人生允许彷徨,但不允许蹉跎.
8.order by按聚集索引列排序效率最高排序是较耗时的操作,应尽量简化或避免对大型表进行排序,如缩小排序的列的范围,只在有索引的列上排序等等。我们来看:(gid是主键,fariqi是聚合索引列)select top 10000 gid,fariqi,reader,title from tgongwen用时:196 毫秒。 扫描计数 1,逻辑读 289 次,物理读 1 次,预读 1527 次。
select top 10000 gid,fariqi,reader,title from tgongwen order by gid asc用时:4720毫秒。 扫描计数 1,逻辑读 41956 次,物理读 0 次,预读 1287 次。
select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc用时:4736毫秒。 扫描计数 1,逻辑读 55350 次,物理读 10 次,预读 775 次。
select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi asc用时:173毫秒。 扫描计数 1,逻辑读 290 次,物理读 0 次,预读 0 次。
select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi desc用时:156毫秒。 扫描计数 1,逻辑读 289 次,物理读 0 次,预读 0 次。
同时,按照某个字段进行排序的时候,无论是正序还是倒序,速度是基本相当的。
********************************************************
9.关于节省数据查询系统开销方面的措施 (1)使用TOP尽量减少取出的数据量 (2)字段提取要按照“需多少、提多少”的原则,避免“select *”字段大小越大,数目越多,select所耗费的资源就越多,比如取int类型的字段就会比取char的快很多。我们每少提取一个字段,数据的提取速度就会有相应的提升。提升的幅度根据舍弃的字段的大小来判断 (3)count(*) 与 count(字段) 方法比较 用 count(*)和用 count(主键)的速度是相当的,而count(*)却比其他任何除主键以外的字段汇总速度要快,而且字段越长,汇总速度就越 慢。如果用 count(*), SQL SERVER会自动查找最小字段来汇总。当然,如果您直接写count(主键)将会来的更直接些 (4)有嵌套查询时,尽可能在内层过滤掉数据 如果一个列同时在主查询和where子句中出现,很可能当主查询中的列值改变之后,子查询必须重新查询一次。而且查询嵌套层次越多,效率越低,因此应当尽量避免子查询。如果子查询不可避免,那么要在子查询中过滤掉尽可能多的行 (5)多表关联查询时,需注意表顺序,并尽可能早的过滤掉数据 在使用Join进行多表关联查询时候,应该使用系统开销最小的方案。连接条件要充份考虑带有索引的表、行数多的表,并注意优化表顺序;说的简单一点,就是尽可能早的将之后要做关联的数据量降下来。
一般情况下,sqlserver 会对表的连接作出自动优化。例如: select name,no from A join B on A. id=B.id join C on C.id=A.id where name=‘wang‘ 尽 管A表在From中先列出,然后才是B,最后才是C。但sql server可能会首先使用c表。它的选择原则是相对于该查询限制为单行或少数几行,就可 以减少在其他表中查找的总数据量。绝大多数情况下,sql server 会作出最优的选择,但如果你发觉某个复杂的联结查询速度比预计的要慢,就可以使 用SET FORCEPLAN语句强制sql server按照表出现顺序使用表。如上例加 上:SET FORCEPLAN ON…….SET FORCEPLAN OFF 表的执行顺序将会按照你所写的顺序执行。在查询分析器中查看2种执行效 率,从而选择表的连接顺序。SET FORCEPLAN的缺点是只能在存储过程中使用
原文:http://hi.baidu.com/mayw1985/item/2092f0427fcdf5e6dc0f6cab
SQLSERVER2008R2正确使用索引
标签:构建 支持 计数 嵌套 等等 完全 工作 编码 语句
小编还为您整理了以下内容,可能对您也有帮助:
sqlserver 2008 怎么建立索引
什么是索引
拿汉语字典的目录页(索引)打比方:正如汉语字典中的汉字按页存放一样,SQL Server中的数据记录也是按页存放的,每页容量一般为4K 。为了加快查找的速度,汉语字(词)典一般都有按拼音、笔画、偏旁部首等排序的目录(索引),我们可以选择按拼音或笔画查找方式,快速查找到需要的字(词)。
同理,SQL Server允许用户在表中创建索引,指定按某列预先排序,从而大大提高查询速度。
• SQL Server中的数据也是按页( 4KB )存放
• 索引:是SQL Server编排数据的内部方法。它为SQL Server提供一种方法来编排查询数据。
• 索引页:数据库中存储索引的数据页;索引页类似于汉语字(词)典中按拼音或笔画排序的目录页。
• 索引的作用:通过使用索引,可以大大提高数据库的检索速度,改善数据库性能。
索引类型
• 唯一索引:唯一索引不允许两行具有相同的索引值
• 主键索引:为表定义一个主键将自动创建主键索引,主键索引是唯一索引的特殊类型。主键索引要求主键中的每个值是唯一的,并且不能为空
• 聚集索引(Clustered):表中各行的物理顺序与键值的逻辑(索引)顺序相同,每个表只能有一个
• 非聚集索引(Non-clustered):非聚集索引指定表的逻辑顺序。数据存储在一个位置,索引存储在另一个位置,索引中包含指向数据存储位置的指针。可以有多个,小于249个
索引类型:再次用汉语字典打比方,希望大家能够明白聚集索引和非聚集索引这两个概念。
唯一索引:
唯一索引不允许两行具有相同的索引值。
如果现有数据中存在重复的键值,则大多数数据库都不允许将新创建的唯一索引与表一起保存。当新数据将使表中的键值重复时,数据库也拒绝接受此数据。例如,如果在stuInfo表中的学员员身份证号(stuID) 列上创建了唯一索引,则所有学员的身份证号不能重复。
提示:创建了唯一约束,将自动创建唯一索引。尽管唯一索引有助于找到信息,但为了获得最佳性能,建议使用主键约束或唯一约束。
主键索引:
在数据库关系图中为表定义一个主键将自动创建主键索引,主键索引是唯一索引的特殊类型。主键索引要求主键中的每个值是唯一的。当在查询中使用主键索引时,它还允许快速访问数据。
聚集索引(clustered index)
在聚集索引中,表中各行的物理顺序与键值的逻辑(索引)顺序相同。表只能包含一个聚集索引。例如:汉语字(词)典默认按拼音排序编排字典中的每页页码。拼音字母a,b,c,d……x,y,z就是索引的逻辑顺序,而页码1,2,3……就是物理顺序。默认按拼音排序的字典,其索引顺序和逻辑顺序是一致的。即拼音顺序较后的字(词)对应的页码也较大。如拼音“ha”对应的字(词)页码就比拼音“ba” 对应的字(词)页码靠后。
非聚集索引(Non-clustered)
如果不是聚集索引,表中各行的物理顺序与键值的逻辑顺序不匹配。聚集索引比非聚集索引(nonclustered index)有更快的数据访问速度。例如,按笔画排序的索引就是非聚集索引,“1”画的字(词)对应的页码可能比“3”画的字(词)对应的页码大(靠后)。
提示:SQL Server中,一个表只能创建1个聚集索引,多个非聚集索引。设置某列为主键,该列就默认为聚集索引
如何创建索引
使用T-SQL语句创建索引的语法:
CREATE [UNIQUE] [CLUSTERED|NONCLUSTERED]
INDEX index_name
ON table_name (column_name…)
[WITH FILLFACTOR=x]
q UNIQUE表示唯一索引,可选
q CLUSTERED、NONCLUSTERED表示聚集索引还是非聚集索引,可选
q FILLFACTOR表示填充因子,指定一个0到100之间的值,该值指示索引页填满的空间所占的百分比
在stuMarks表的writtenExam列创建索引:
USE stuDB
GO
IF EXISTS (SELECT name FROM sysindexes
WHERE name = 'IX_writtenExam')
DROP INDEX stuMarks.IX_writtenExam
/*--笔试列创建非聚集索引:填充因子为30%--*/
CREATE NONCLUSTERED INDEX IX_writtenExam
ON stuMarks(writtenExam)
WITH FILLFACTOR= 30
GO
/*-----指定按索引 IX_writtenExam 查询----*/
SELECT * FROM stuMarks (INDEX=IX_writtenExam)
WHERE writtenExam BETWEEN 60 AND 90
虽然我们可以指定SQL Server按哪个索引进行数据查询,但一般不需要我们人工指定。SQL Server将会根据我们创建的索引,自动优化查询。
索引的优缺点
• 优点
– 加快访问速度
– 加强行的唯一性
• 缺点
– 带索引的表在数据库中需要更多的存储空间
– 操纵数据的命令需要更长的处理时间,因为它们需要对索引进行更新
创建索引的指导原则
• 请按照下列标准选择建立索引的列。
– 该列用于频繁搜索
– 该列用于对数据进行排序
• 请不要使用下面的列创建索引:
– 列中仅包含几个不同的值。
– 表中仅包含几行。为小型表创建索引可能不太划算,因为SQL Server在索引中搜索数据所花的时间比在表中逐行搜索所花的时间更长
sql server索引怎么用
1、打开 SQL Server Management Studio并连接到数据库引擎数据库。
2、在“对象资源管理器”窗格中展开“数据库”节点。再打开“数据库”节点下的“表”节点,再展开dbo.格式的表。
3、右击“索引”选项,在弹出的快捷菜单中选择“新建索引”命令。
4、在打开的“新建索引”对话框中,设置索引的名称,索引类型为“聚集”, 然后单击“添加”按钮。
5、在打开的 “从dbo.表 中选择列” 对话框中选择要添加到索引键的表列。 然后点击“确定”按钮。
6、选择索引键后的“新建索引”对话框中,设置索引列的排序为“升序/降序”,设置完成后,单击“新建索引”对话框的“确定”按钮,这样就为表创建了索引。
sql server索引怎么用
1、打开 SQL Server Management Studio并连接到数据库引擎数据库。
2、在“对象资源管理器”窗格中展开“数据库”节点。再打开“数据库”节点下的“表”节点,再展开dbo.格式的表。
3、右击“索引”选项,在弹出的快捷菜单中选择“新建索引”命令。
4、在打开的“新建索引”对话框中,设置索引的名称,索引类型为“聚集”, 然后单击“添加”按钮。
5、在打开的 “从dbo.表 中选择列” 对话框中选择要添加到索引键的表列。 然后点击“确定”按钮。
6、选择索引键后的“新建索引”对话框中,设置索引列的排序为“升序/降序”,设置完成后,单击“新建索引”对话框的“确定”按钮,这样就为表创建了索引。
在SQLServer中使用索引的技巧
在SQL Server中 为了查询性能的优化 有时我们就需要对数据表通过建立索引的方式 目的主要是根据查询要求 迅速缩小查询范围 避免全表扫描
索引有两种类型 分别是聚集索引(clustered index 也称聚类索引 簇集索引)和非聚集索引(nonclustered index 也称非聚类索引 非簇集索引)
聚集索引在一个表中只能有一个 默认情况下在主键建立的时候创建 它是规定数据在表中的物理存储顺序 我们也可以取消主键的聚集索引 所以必须考虑数据库可能用到的查询类型以及使用的最为频繁的查询类型 对其最常用的一个字段或者多个字段建立聚集索引或者组合的聚集索引 它就是SQL Server会在物理上按升序(默认)或者降序重排数据列 这样就可以迅速的找到被查询的数据
非聚集索主要是数据存储在一个地方 索引存储在另一个地方 索引带有指针指向数据的存储位置 索引中的项目按索引键值的顺序存储 而表中的信息按另一种顺序存储 可以在一个表格中使用高达 个非聚集的索引 在查询的过程中先对非聚集索引进行搜索 找到数据值在表中的位置 然后从该位置直接检索数据 这使非聚集索引成为精确匹配查询的最佳方法 因为索引包含描述查询所搜索的数据值在表中的精确位置的条目
所以我们在选择创建聚集索引的时候要注意以下几个方面
) 对表建立主键时 就会为主键自动添加了聚集索引 如自动编号字段 而我们没有必要把聚集索引浪费在主键上 除非你只按主键查询 所以会把聚集索引设置在按条件查询频率最高的那个字段或者组合的字段
) 索引的建立要根据实际应用的需求来进行 并非是在任何字段上建立索引就能提高查询速度 聚集索引建立遵循下面几个原则
包含大量非重复值的列
使用下列运算符返回一个范围值的查询 BEEEN > >= < 和 <=
被连续访问的列
返回大型结果集的查询
经常被使用联接或 GROUP BY 子句的查询访问的列;一般来说 这些是外键列 对ORDER BY 或 GROUP BY 子句中指定的列进行索引 可以使 SQL Server 不必对数据进行排序 因为这些行已经排序 这样可以提高查询性能
OLTP 类型的应用程序 这些程序要求进行非常快速的单行查找(一般通过主键) 应在主键上创建聚集索引
举例来说 银行交易日志中对交易日期建立聚合索引 数据物理上按顺序存于数据页上 重复值也排列在一起 因而在范围查找时 可以先找到这个范围的起末点 且只在这个范围内扫描数据页 避免了大范围扫描 提高了查询速度 而如果我们对员工的基本信息表中性别的字段列上建立聚集索引 就完全没有必要 因为内容里只涉及到 男 与 女 两个不同值
) 在聚集索引中按常用的组合字段建立索引 形成复合索引 一般在为表建立多个主键的时候就会产生 如果一个表中的数据在查询时有多个字段总是同时出现则这些字段就可以作为复合索引 这样能形成索引覆盖 提高where语句的查询效率
)索引对查询有一这的优化 但由于改变一个表的内容 将会引起索引的变化 频繁的对数据操作如insert update delete语句将导致系统花费较大的代价进行索引更新 引起整体性能的下降 一般来讲 在对查询性能的要求高于对数据维护性能要求时 应该尽量使用索引 有时在这种操作数据库比较频繁的某些极端情况下 可先删除索引 再对数据库表更新大量数据 最后再重建索引 新建立的索引总是比较好用
索引在使用了长久的时候 就会产生很多的碎片 查询的性能就会受到影响 这时候有两种方法解决 一是利用DBCC INDEXDEFRAG整理索引碎片 还有就是利用DBCC DBREINDEX重建索引
DBCC INDEXDEFRAG 命令是联机操作 所以索引只有在该命令正在运行时才可用 而且可以在不丢失已完成工作的情况下中断该操作 这种方法的缺点是在重新组织数据方面没有聚集索引的除去/重新创建操作有效
重新创建聚集索引将对数据进行重新组织 其结果是使数据页填满 填满程度可以使用 FILLFACTOR 选项进行配置 这种方法的缺点是索引在除去/重新创建周期内为脱机状态 并且操作属原子级 如果中断索引创建 则不会重新创建该索引
我们来看看索引重建使用的方法
语法 DBCC DBREINDEX ( [ TableName [ index_name [ fillfactor ] ] ] )
参数 TableName
是要重建其指定的索引的表名 数据库 所有者和表名必须符合标识符的规则 有关更多信息 请参见使用标识符 如果提供 database 或 owner 部分 则必须使用单引号 ( )
将整个 database owner table_name 括起来 如果只指定 table_name 则不需要单引号
index_name 是要重建的索引名 索引名必须符合标识符的规则 如果未指定 index_name 或指定为 就要对表的所有索引进行重建
fillfactor 是创建索引时每个索引页上要用于存储数据的空间百分比 fillfactor替换起始填充因子以作为索引或任何其它重建的非聚集索引(因为已重建聚集索引)的新默认值 如果 fillfactor 为 DBCC DBREINDEX 在创建索引时将使用指定的起始fillfactor
我们在查询分析器中输入如下的命令
DBCC DBREINDEX ( MyTable )
lishixin/Article/program/SQLServer/201311/22210在SQLServer中使用索引的技巧
在SQL Server中 为了查询性能的优化 有时我们就需要对数据表通过建立索引的方式 目的主要是根据查询要求 迅速缩小查询范围 避免全表扫描
索引有两种类型 分别是聚集索引(clustered index 也称聚类索引 簇集索引)和非聚集索引(nonclustered index 也称非聚类索引 非簇集索引)
聚集索引在一个表中只能有一个 默认情况下在主键建立的时候创建 它是规定数据在表中的物理存储顺序 我们也可以取消主键的聚集索引 所以必须考虑数据库可能用到的查询类型以及使用的最为频繁的查询类型 对其最常用的一个字段或者多个字段建立聚集索引或者组合的聚集索引 它就是SQL Server会在物理上按升序(默认)或者降序重排数据列 这样就可以迅速的找到被查询的数据
非聚集索主要是数据存储在一个地方 索引存储在另一个地方 索引带有指针指向数据的存储位置 索引中的项目按索引键值的顺序存储 而表中的信息按另一种顺序存储 可以在一个表格中使用高达 个非聚集的索引 在查询的过程中先对非聚集索引进行搜索 找到数据值在表中的位置 然后从该位置直接检索数据 这使非聚集索引成为精确匹配查询的最佳方法 因为索引包含描述查询所搜索的数据值在表中的精确位置的条目
所以我们在选择创建聚集索引的时候要注意以下几个方面
) 对表建立主键时 就会为主键自动添加了聚集索引 如自动编号字段 而我们没有必要把聚集索引浪费在主键上 除非你只按主键查询 所以会把聚集索引设置在按条件查询频率最高的那个字段或者组合的字段
) 索引的建立要根据实际应用的需求来进行 并非是在任何字段上建立索引就能提高查询速度 聚集索引建立遵循下面几个原则
包含大量非重复值的列
使用下列运算符返回一个范围值的查询 BEEEN > >= < 和 <=
被连续访问的列
返回大型结果集的查询
经常被使用联接或 GROUP BY 子句的查询访问的列;一般来说 这些是外键列 对ORDER BY 或 GROUP BY 子句中指定的列进行索引 可以使 SQL Server 不必对数据进行排序 因为这些行已经排序 这样可以提高查询性能
OLTP 类型的应用程序 这些程序要求进行非常快速的单行查找(一般通过主键) 应在主键上创建聚集索引
举例来说 银行交易日志中对交易日期建立聚合索引 数据物理上按顺序存于数据页上 重复值也排列在一起 因而在范围查找时 可以先找到这个范围的起末点 且只在这个范围内扫描数据页 避免了大范围扫描 提高了查询速度 而如果我们对员工的基本信息表中性别的字段列上建立聚集索引 就完全没有必要 因为内容里只涉及到 男 与 女 两个不同值
) 在聚集索引中按常用的组合字段建立索引 形成复合索引 一般在为表建立多个主键的时候就会产生 如果一个表中的数据在查询时有多个字段总是同时出现则这些字段就可以作为复合索引 这样能形成索引覆盖 提高where语句的查询效率
)索引对查询有一这的优化 但由于改变一个表的内容 将会引起索引的变化 频繁的对数据操作如insert update delete语句将导致系统花费较大的代价进行索引更新 引起整体性能的下降 一般来讲 在对查询性能的要求高于对数据维护性能要求时 应该尽量使用索引 有时在这种操作数据库比较频繁的某些极端情况下 可先删除索引 再对数据库表更新大量数据 最后再重建索引 新建立的索引总是比较好用
索引在使用了长久的时候 就会产生很多的碎片 查询的性能就会受到影响 这时候有两种方法解决 一是利用DBCC INDEXDEFRAG整理索引碎片 还有就是利用DBCC DBREINDEX重建索引
DBCC INDEXDEFRAG 命令是联机操作 所以索引只有在该命令正在运行时才可用 而且可以在不丢失已完成工作的情况下中断该操作 这种方法的缺点是在重新组织数据方面没有聚集索引的除去/重新创建操作有效
重新创建聚集索引将对数据进行重新组织 其结果是使数据页填满 填满程度可以使用 FILLFACTOR 选项进行配置 这种方法的缺点是索引在除去/重新创建周期内为脱机状态 并且操作属原子级 如果中断索引创建 则不会重新创建该索引
我们来看看索引重建使用的方法
语法 DBCC DBREINDEX ( [ TableName [ index_name [ fillfactor ] ] ] )
参数 TableName
是要重建其指定的索引的表名 数据库 所有者和表名必须符合标识符的规则 有关更多信息 请参见使用标识符 如果提供 database 或 owner 部分 则必须使用单引号 ( )
将整个 database owner table_name 括起来 如果只指定 table_name 则不需要单引号
index_name 是要重建的索引名 索引名必须符合标识符的规则 如果未指定 index_name 或指定为 就要对表的所有索引进行重建
fillfactor 是创建索引时每个索引页上要用于存储数据的空间百分比 fillfactor替换起始填充因子以作为索引或任何其它重建的非聚集索引(因为已重建聚集索引)的新默认值 如果 fillfactor 为 DBCC DBREINDEX 在创建索引时将使用指定的起始fillfactor
我们在查询分析器中输入如下的命令
DBCC DBREINDEX ( MyTable )
lishixin/Article/program/SQLServer/201311/22210在SQL中怎样用指定索引查询?
SQL索引在数据库优化中占有一个非常大的比例, 一个好的索引的设计,可以让你的效率提高几十甚至几百倍,在这里将带你一步步揭开他的神秘面纱。
1.1 什么是索引?
SQL索引有两种,聚集索引和非聚集索引,索引主要目的是提高了SQL Server系统的性能,加快数据的查询速度与减少系统的响应时间
下面举两个简单的例子:
图书馆的例子:一个图书馆那么多书,怎么管理呢?建立一个字母开头的目录,例如:a开头的书,在第一排,b开头的在第二排,这样在找什么书就好说了,这个就是一个聚集索引,可是很多人借书找某某作者的,不知道书名怎么办?图书管理员在写一个目录,某某作者的书分别在第几排,第几排,这就是一个非聚集索引
字典的例子:字典前面的目录,可以按照拼音和部首去查询,我们想查询一个字,只需要根据拼音或者部首去查询,就可以快速的定位到这个汉字了,这个就是索引的好处,拼音查询法就是聚集索引,部首查询就是一个非聚集索引.
看了上面的例子,下面的一句话大家就很容易理解了:聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物理存储并不连续。就像字段,聚集索引是连续的,a后面肯定是b,非聚集索引就不连续了,就像图书馆的某个作者的书,有可能在第1个货架上和第10个货架上。还有一个小知识点就是:聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个。
1.2 索引的存储机制
首先,无索引的表,查询时,是按照顺序存续的方法扫描每个记录来查找符合条件的记录,这样效率十分低下,举个例子,如果我们将字典的汉字随即打乱,没有前面的按照拼音或者部首查询,那么我们想找一个字,按照顺序的方式去一页页的找,这样效率有多底,大家可以想象。
聚集索引和非聚集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致,其实理解起来非常简单,还是举字典的例子:如果按照拼音查询,那么都是从a-z的,是具有连续性的,a后面就是b,b后面就是c, 聚集索引就是这样的,他是和表的物理排列顺序是一样的,例如有id为聚集索引,那么1后面肯定是2,2后面肯定是3,所以说这样的搜索顺序的就是聚集索引。非聚集索引就和按照部首查询是一样是,可能按照偏房查询的时候,根据偏旁‘弓’字旁,索引出两个汉字,张和弘,但是这两个其实一个在100页,一个在1000页,(这里只是举个例子),他们的索引顺序和数据库表的排列顺序是不一样的,这个样的就是非聚集索引。
原理明白了,那他们是怎么存储的呢?在这里简单的说一下,聚集索引就是在数据库被开辟一个物理空间存放他的排列的值,例如1-100,所以当插入数据时,他会重新排列整个整个物理空间,而非聚集索引其实可以看作是一个含有聚集索引的表,他只仅包含原表中非聚集索引的列和指向实际物理表的指针。他只记录一个指针,其实就有点和堆栈差不多的感觉了
1.3 什么情况下设置索引
动作描述 | 使用聚集索引 | 使用非聚集索引 |
外键列 | 应 | 应 |
主键列 | 应 | 应 |
列经常被分组排序(order by) | 应 | 应 |
返回某范围内的数据 | 应 | 不应 |
小数目的不同值 | 应 | 不应 |
大数目的不同值 | 不应 | 应 |
频繁更新的列 | 不应 | 应 |
频繁修改索引列 | 不应 | 应 |
一个或极少不同值 | 不应 | 不应 |
建立索引的原则:
1) 定义主键的数据列一定要建立索引。
2) 定义有外键的数据列一定要建立索引。
3) 对于经常查询的数据列最好建立索引。
4) 对于需要在指定范围内的快速或频繁查询的数据列;
5) 经常用在WHERE子句中的数据列。
6) 经常出现在关键字order by、group by、distinct后面的字段,建立索引。如果建立的是复合索引,索引的字段顺序要和这些关键字后面的字段顺序一致,否则索引不会被使用。
7) 对于那些查询中很少涉及的列,重复值比较多的列不要建立索引。
8) 对于定义为text、image和bit的数据类型的列不要建立索引。
9) 对于经常存取的列避免建立索引
9) 限制表上的索引数目。对一个存在大量更新操作的表,所建索引的数目一般不要超过3个,最多不要超过5个。索引虽说提高了访问速度,但太多索引会影响数据的更新操作。
10) 对复合索引,按照字段在查询条件中出现的频度建立索引。在复合索引中,记录首先按照第一个字段排序。对于在第一个字段上取值相同的记录,系统再按照第二个字段的取值排序,以此类推。因此只有复合索引的第一个字段出现在查询条件中,该索引才可能被使用,因此将应用频度高的字段,放置在复合索引的前面,会使系统最大可能地使用此索引,发挥索引的作用。
1.4 如何创建索引
1.41 创建索引的语法:
CREATE [UNIQUE][CLUSTERED | NONCLUSTERED] INDEX index_name
ON {table_name | view_name} [WITH [index_property [,....n]]
说明:
UNIQUE: 建立唯一索引。
CLUSTERED: 建立聚集索引。
NONCLUSTERED: 建立非聚集索引。
Index_property: 索引属性。
UNIQUE索引既可以采用聚集索引结构,也可以采用非聚集索引的结构,如果不指明采用的索引结构,则SQL Server系统默认为采用非聚集索引结构。
1.42 删除索引语法:
DROP INDEX table_name.index_name[,table_name.index_name]
说明:table_name: 索引所在的表名称。
index_name : 要删除的索引名称。
1.43 显示索引信息:
使用系统存储过程:sp_helpindex 查看指定表的索引信息。
执行代码如下:
Exec sp_helpindex book1;
1.5 索引使用次数、索引效率、占用CPU检测、索引缺失
当我们明白了什么是索引,什么时间创建索引以后,我们就会想,我们创建的索引到底效率执行的怎么样?好不好?我们创建的对不对?
首先我们来认识一下DMV,DMV (dynamic management view)动态管理视图和函数返回特定于实现的内部状态数据。推出SQL Server 2005时,微软介绍了许多被称为dmvs的系统视图,让您可以探测SQL Server 的健康状况,诊断问题,或查看SQL Server实例的运行信息。统计数据是在SQL Server运行的时候开始收集的,并且在SQL Server每次启动的时候,统计数据将会被重置。当你删除或者重新创建其组件时,某些dmv的统计数据也可以被重置,例如存储过程和表,而其它的dmv信息在运行dbcc命令时也可以被重置。
当你使用一个dmv时,你需要紧记SQL Server收集这些信息有多长时间了,以确定这些从dmv返回的数据到底有多少可用性。如果SQL Server只运行了很短的一段时间,你可能不想去使用一些dmv统计数据,因为他们并不是一个能够代表SQL Server实例可能遇到的真实工作负载的样本。另一方面,SQL Server只能维持一定量的信息,有些信息在进行SQL Server性能管理活动的时候可能丢失,所以如果SQL Server已经运行了相当长的一段时间,一些统计数据就有可能已被覆盖。
因此,任何时候你使用dmv,当你查看从SQL Server 2005的dmvs返回的相关资料时,请务必将以上的观点装在脑海中。只有当你确信从dmvs获得的信息是准确和完整的,你才能变更数据库或者应用程序代码。
下面就看一下dmv到底能带给我们那些好的功能呢?
1.51 :索引使用次数
我们下看一下下面两种查询方式返回的结果(这两种查询的查询用途一致)
①----
declare @dbid int
select @dbid = db_id()
select objectname=object_name(s.object_id), s.object_id, indexname=i.name, i.index_id
, user_seeks, user_scans, user_lookups, user_updates
from sys.dm_db_index_usage_stats s,
sys.indexes i
where database_id = @dbid and objectproperty(s.object_id,‘IsUserTable‘) = 1
and i.object_id = s.object_id
and i.index_id = s.index_id
order by (user_seeks + user_scans + user_lookups + user_updates) asc
返回查询结果
②:使用多的索引排在前面
SELECT objects.name ,
databases.name ,
indexes.name ,
user_seeks ,
user_scans ,
user_lookups ,
partition_stats.row_count
FROM sys.dm_db_index_usage_stats stats
LEFT JOIN sys.objects objects ON stats.object_id = objects.object_id
LEFT JOIN sys.databases databases ON databases.database_id = stats.database_id
LEFT JOIN sys.indexes indexes ON indexes.index_id = stats.index_id
AND stats.object_id = indexes.object_id
LEFT JOIN sys.dm_db_partition_stats partition_stats ON stats.object_id = partition_stats.object_id
AND indexes.index_id = partition_stats.index_id
WHERE 1 = 1
--AND databases.database_id = 7
AND objects.name IS NOT NULL
AND indexes.name IS NOT NULL
AND user_scans>0
ORDER BY user_scans DESC ,
stats.object_id ,
indexes.index_id
返回查询结果
user_seeks : 通过用户查询执行的搜索次数。
个人理解: 此统计索引搜索的次数
user_scans: 通过用户查询执行的扫描次数。
个人理解:此统计表扫描的次数,无索引配合
user_lookups: 通过用户查询执行的查找次数。
个人理解:用户通过索引查找,在使用RID或聚集索引查找数据的次数,对于堆表或聚集表数据而言和索引配合使用次数
user_updates: 通过用户查询执行的更新次数。
个人理解:索引或表的更新次数
我们可以清晰的看到,那些索引用的多,那些索引没用过,大家可以根据查询出来的东西去分析自己的数据索引和表
1.52 :索引提高了多少性能
新建了索引到底增加了多少数据的效率呢?到底提高了多少性能呢?运行如下SQL可以返回连接缺失索引动态管理视图,发现最有用的索引和创建索引的方法:
SELECT
avg_user_impact AS average_improvement_percentage,
avg_total_user_cost AS average_cost_of_query_without_missing_index,
‘CREATE INDEX ix_‘ + [statement] +
ISNULL(equality_columns, ‘_‘) +
ISNULL(inequality_columns, ‘_‘) + ‘ ON ‘ + [statement] +
‘ (‘ + ISNULL(equality_columns, ‘ ‘) +
ISNULL(inequality_columns, ‘ ‘) + ‘)‘ +
ISNULL(‘ INCLUDE (‘ + included_columns + ‘)‘, ‘‘)
AS create_missing_index_command
FROM sys.dm_db_missing_index_details a INNER JOIN
sys.dm_db_missing_index_groups b ON a.index_handle = b.index_handle
INNER JOIN sys.dm_db_missing_index_group_stats c ON
b.index_group_handle = c.group_handle
WHERE avg_user_impact > = 40
返回结果
虽然用户能够修改性能提高的百分比,但以上查询返回所有能够将性能提高40%或更高的索引。你可以清晰的看到每个索引提高的性能和效率了
1.53 :最占用CPU、执行时间最长命令
这个和索引无关,但是还是在这里提出来,因为他也属于DMV带给我们的功能吗,他可以让你轻松查询出,那些sql语句占用你的cpu最高
SELECT TOP 100 execution_count,
total_logical_reads /execution_count AS [Avg Logical Reads],
total_elapsed_time /execution_count AS [Avg Elapsed Time],
db_name(st.dbid) as [database name],
object_name(st.dbid) as [object name],
object_name(st.objectid) as [object name 1],
SUBSTRING(st.text, (qs.statement_start_offset / 2) + 1,
((CASE statement_end_offset WHEN - 1 THEN DATALENGTH(st.text) ELSE qs.statement_end_offset END - qs.statement_start_offset)
/ 2) + 1) AS statement_text
FROM sys.dm_exec_query_stats AS qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
WHERE execution_count > 100
ORDER BY 1 DESC;
返回结果:
执行时间最长的命令
SELECT TOP 10 COALESCE(DB_NAME(st.dbid),
DB_NAME(CAST(pa.value as int))+‘*‘,
‘Resource‘) AS DBNAME,
SUBSTRING(text,
-- starting value for substring
CASE WHEN statement_start_offset = 0
OR statement_start_offset IS NULL
THEN 1
ELSE statement_start_offset/2 + 1 END,
-- ending value for substring
CASE WHEN statement_end_offset = 0
OR statement_end_offset = -1
OR statement_end_offset IS NULL
THEN LEN(text)
ELSE statement_end_offset/2 END -
CASE WHEN statement_start_offset = 0
OR statement_start_offset IS NULL
THEN 1
ELSE statement_start_offset/2 END + 1
) AS TSQL,
total_logical_reads/execution_count AS AVG_LOGICAL_READS
FROM sys.dm_exec_query_stats
CROSS APPLY sys.dm_exec_sql_text(sql_handle) st
OUTER APPLY sys.dm_exec_plan_attributes(plan_handle) pa
WHERE attribute = ‘dbid‘
ORDER BY AVG_LOGICAL_READS DESC ;
看到了吗?直接可以定位到你的sql语句,优化去吧。还等什么呢?
1.54:缺失索引
缺失索引就是帮你查找你的数据库缺少什么索引,告诉你那些字段需要加上索引,这样你就可以根据提示添加你数据库缺少的索引了
SELECT TOP 10
[Total Cost] = ROUND(avg_total_user_cost * avg_user_impact * (user_seeks + user_scans),0)
, avg_user_impact
, TableName = statement
, [EqualityUsage] = equality_columns
, [InequalityUsage] = inequality_columns
, [Include Cloumns] = included_columns
FROM sys.dm_db_missing_index_groups g
INNER JOIN sys.dm_db_missing_index_group_stats s
ON s.group_handle = g.index_group_handle
INNER JOIN sys.dm_db_missing_index_details d
ON d.index_handle = g.index_handle
ORDER BY [Total Cost] DESC;
查询结果如下:
1.6 适当创建索引覆盖
假设你在Sales表(SelesID,SalesDate,SalesPersonID,ProductID,Qty)的外键列(ProductID)上创建了一个索引,假设ProductID列是一个高选中性列,那么任何在where子句中使用索引列(ProductID)的select查询都会更快,如果在外键上没有创建索引,将会发生全部扫描,但还有办法可以进一步提升查询性能。
假设Sales表有10,000行记录,下面的SQL语句选中400行(总行数的4%):
SELECT SalesDate, SalesPersonID FROM Sales WHERE ProductID = 112
我们来看看这条SQL语句在SQL执行引擎中是如何执行的:
1)Sales表在ProductID列上有一个非聚集索引,因此它查找非聚集索引树找出ProductID=112的记录;
2)包含ProductID = 112记录的索引页也包括所有的聚集索引键(所有的主键键值,即SalesID);
3)针对每一个主键(这里是400),SQL Server引擎查找聚集索引树找出真实的行在对应页面中的位置;
SQL Server引擎从对应的行查找SalesDate和SalesPersonID列的值。
在上面的步骤中,对ProductID = 112的每个主键记录(这里是400),SQL Server引擎要搜索400次聚集索引树以检索查询中指定的其它列(SalesDate,SalesPersonID)。
如果非聚集索引页中包括了聚集索引键和其它两列(SalesDate,,SalesPersonID)的值,SQL Server引擎可能不会执行上面的第3和4步,直接从非聚集索引树查找ProductID列速度还会快一些,直接从索引页读取这三列的数值。
幸运的是,有一种方法实现了这个功能,它被称为“覆盖索引”,在表列上创建覆盖索引时,需要指定哪些额外的列值需要和聚集索引键值(主键)一起存储在索引页中。下面是在Sales 表ProductID列上创建覆盖索引的例子:
CREATE INDEX NCLIX_Sales_ProductID--Index name
ON dbo.Sales(ProductID)--Column on which index is to be created
INCLUDE(SalesDate, SalesPersonID)--Additional column values to include
应该在那些select查询中常使用到的列上创建覆盖索引,但覆盖索引中包括过多的列也不行,因为覆盖索引列的值是存储在内存中的,这样会消耗过多内存,引发性能下降。
1.7 索引碎片
在数据库性能优化一:数据库自身优化一文中已经讲到了这个问题,再次就不做过多的重复地址:http://www.cnblogs.com/AK2012/archive/2012/12/25/2012-1228.html
1.8 索引实战(摘抄)
之所以这章摘抄,是因为下面这个文章已经写的太好了,估计我写出来也无法比这个好了,所以就摘抄了
人们在使用SQL时往往会陷入一个误区,即太关注于所得的结果是否正确,而忽略了不同的实现方法之间可能存在的性能差异,这种性能差异在大型的或是复杂的数据库环境中(如联机事务处理OLTP或决策支持系统DSS)中表现得尤为明显。
笔者在工作实践中发现,不良的SQL往往来自于不恰当的索引设计、不充份的连接条件和不可优化的where子句。
在对它们进行适当的优化后,其运行速度有了明显地提高!
下面我将从这三个方面分别进行总结:
为了更直观地说明问题,所有实例中的SQL运行时间均经过测试,不超过1秒的均表示为(< 1秒)。----
测试环境: 主机:HP LH II---- 主频:330MHZ---- 内存:128兆----
操作系统:Operserver5.0.4----
数据库:Sybase11.0.3
一、不合理的索引设计----
例:表record有620000行,试看在不同的索引下,下面几个 SQL的运行情况:
---- 1.在date上建有一非个群集索引
select count(*) from record where date >‘19991201‘ and date < ‘19991214‘and amount >2000 (25秒)
select date ,sum(amount) from record group by date(55秒)
select count(*) from record where date >‘19990901‘ and place in (‘BJ‘,‘SH‘) (27秒)
---- 分析:----
date上有大量的重复值,在非群集索引下,数据在物理上随机存放在数据页上,在范围查找时,必须执行一次表扫描才能找到这一范围内的全部行。
---- 2.在date上的一个群集索引
select count(*) from record where date >‘19991201‘ and date < ‘19991214‘ and amount >2000 (14秒)
select date,sum(amount) from record group by date(28秒)
select count(*) from record where date >‘19990901‘ and place in (‘BJ‘,‘SH‘)(14秒)
---- 分析:---- 在群集索引下,数据在物理上按顺序在数据页上,重复值也排列在一起,因而在范围查找时,可以先找到这个范围的起末点,且只在这个范围内扫描数据页,避免了大范围扫描,提高了查询速度。
---- 3.在place,date,amount上的组合索引
select count(*) from record where date >‘19991201‘ and date < ‘19991214‘ and amount >2000 (26秒)
select date,sum(amount) from record group by date(27秒)
select count(*) from record where date >‘19990901‘ and place in (‘BJ, ‘SH‘)(< 1秒)
---- 分析:---- 这是一个不很合理的组合索引,因为它的前导列是place,第一和第二条SQL没有引用place,因此也没有利用上索引;第三个SQL使用了place,且引用的所有列都包含在组合索引中,形成了索引覆盖,所以它的速度是非常快的。
---- 4.在date,place,amount上的组合索引
select count(*) from record where date >‘19991201‘ and date < ‘19991214‘ and amount >2000(< 1秒)
select date,sum(amount) from record group by date(11秒)
select count(*) from record where date >‘19990901‘ and place in (‘BJ‘,‘SH‘)(< 1秒)
---- 分析:---- 这是一个合理的组合索引。它将date作为前导列,使每个SQL都可以利用索引,并且在第一和第三个SQL中形成了索引覆盖,因而性能达到了最优。
---- 5.总结:----
缺省情况下建立的索引是非群集索引,但有时它并不是最佳的;合理的索引设计要建立在对各种查询的分析和预测上。
一般来说:
①.有大量重复值、且经常有范围查询(between, >,< ,>=,< =)和order by、group by发生的列,可考虑建立群集索引;
②.经常同时存取多列,且每列都含有重复值可考虑建立组合索引;
③.组合索引要尽量使关键查询形成索引覆盖,其前导列一定是使用最频繁的列。
二、不充份的连接条件:
例:表card有7896行,在card_no上有一个非聚集索引,表account有191122行,在account_no上有一个非聚集索引,试看在不同的表连接条件下,两个SQL的执行情况:
select sum(a.amount) from account a,card b where a.card_no = b.card_no(20秒)
select sum(a.amount) from account a,card b where a.card_no = b.card_no and a.account_no=b.account_no(< 1秒)
---- 分析:---- 在第一个连接条件下,最佳查询方案是将account作外层表,card作内层表,利用card上的索引,其I/O次数可由以下公式估算为:
外层表account上的22541页+(外层表account的191122行*内层表card上对应外层表第一行所要查找的3页)=595907次I/O
在第二个连接条件下,最佳查询方案是将card作外层表,account作内层表,利用account上的索引,其I/O次数可由以下公式估算为:外层表card上的1944页+(外层表card的7896行*内层表account上对应外层表每一行所要查找的4页)= 33528次I/O
可见,只有充份的连接条件,真正的最佳方案才会被执行。
总结:
1.多表操作在被实际执行前,查询优化器会根据连接条件,列出几组可能的连接方案并从中找出系统开销最小的最佳方案。连接条件要充份考虑带有索引的表、行数多的表;内外表的选择可由公式:外层表中的匹配行数*内层表中每一次查找的次数确定,乘积最小为最佳方案。
2.查看执行方案的方法-- 用set showplanon,打开showplan选项,就可以看到连接顺序、使用何种索引的信息;想看更详细的信息,需用sa角色执行dbcc(3604,310,302)。
三、不可优化的where子句
1.例:下列SQL条件语句中的列都建有恰当的索引,但执行速度却非常慢:
select * from record wheresubstring(card_no,1,4)=‘5378‘(13秒)
select * from record whereamount/30< 1000(11秒)
select * from record whereconvert(char(10),date,112)=‘19991201‘(10秒)
分析:
where子句中对列的任何操作结果都是在SQL运行时逐列计算得到的,因此它不得不进行表搜索,而没有使用该列上面的索引;
如果这些结果在查询编译时就能得到,那么就可以被SQL优化器优化,使用索引,避免表搜索,因此将SQL重写成下面这样:
select * from record where card_no like‘5378%‘(< 1秒)
select * from record where amount< 1000*30(< 1秒)
select * from record where date= ‘1999/12/01‘(< 1秒)
你会发现SQL明显快起来!
2.例:表stuff有200000行,id_no上有非群集索引,请看下面这个SQL:
select count(*) from stuff where id_no in(‘0‘,‘1‘)(23秒)
分析:---- where条件中的‘in‘在逻辑上相当于‘or‘,所以语法分析器会将in (‘0‘,‘1‘)转化为id_no =‘0‘ or id_no=‘1‘来执行。
我们期望它会根据每个or子句分别查找,再将结果相加,这样可以利用id_no上的索引;
但实际上(根据showplan),它却采用了"OR策略",即先取出满足每个or子句的行,存入临时数据库的工作表中,再建立唯一索引以去掉重复行,最后从这个临时表中计算结果。因此,实际过程没有利用id_no上索引,并且完成时间还要受tempdb数据库性能的影响。
实践证明,表的行数越多,工作表的性能就越差,当stuff有620000行时,执行时间竟达到220秒!还不如将or子句分开:
select count(*) from stuff where id_no=‘0‘select count(*) from stuff where id_no=‘1‘
得到两个结果,再作一次加法合算。因为每句都使用了索引,执行时间只有3秒,在620000行下,时间也只有4秒。
或者,用更好的方法,写一个简单的存储过程:
create proc count_stuff asdeclare @a intdeclare @b intdeclare @c intdeclare @d char(10)beginselect @a=count(*) from stuff where id_no=‘0‘select @b=count(*) from stuff where id_no=‘1‘endselect @c=@a+@bselect @d=convert(char(10),@c)print @d
直接算出结果,执行时间同上面一样快!
---- 总结:---- 可见,所谓优化即where子句利用了索引,不可优化即发生了表扫描或额外开销。
1.任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。
2.in、or子句常会使用工作表,使索引失效;如果不产生大量重复值,可以考虑把子句拆开;拆开的子句中应该包含索引。
3.要善于使用存储过程,它使SQL变得更加灵活和高效。
从以上这些例子可以看出,SQL优化的实质就是在结果正确的前提下,用优化器可以识别的语句,充份利用索引,减少表扫描的I/O次数,尽量避免表搜索的发生。其实SQL的性能优化是一个复杂的过程,上述这些只是在应用层次的一种体现,深入研究还会涉及数据库层的资源配置、网络层的流量控制以及操作系统层的总体设计。
1.7索引实战是摘抄网友的文章,引用地址:http://blog.csdn.net/gprime/article/details/1687930
SQL索引
标签:
在SQL中怎样用指定索引查询?
SQL索引在数据库优化中占有一个非常大的比例, 一个好的索引的设计,可以让你的效率提高几十甚至几百倍,在这里将带你一步步揭开他的神秘面纱。
1.1 什么是索引?
SQL索引有两种,聚集索引和非聚集索引,索引主要目的是提高了SQL Server系统的性能,加快数据的查询速度与减少系统的响应时间
下面举两个简单的例子:
图书馆的例子:一个图书馆那么多书,怎么管理呢?建立一个字母开头的目录,例如:a开头的书,在第一排,b开头的在第二排,这样在找什么书就好说了,这个就是一个聚集索引,可是很多人借书找某某作者的,不知道书名怎么办?图书管理员在写一个目录,某某作者的书分别在第几排,第几排,这就是一个非聚集索引
字典的例子:字典前面的目录,可以按照拼音和部首去查询,我们想查询一个字,只需要根据拼音或者部首去查询,就可以快速的定位到这个汉字了,这个就是索引的好处,拼音查询法就是聚集索引,部首查询就是一个非聚集索引.
看了上面的例子,下面的一句话大家就很容易理解了:聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物理存储并不连续。就像字段,聚集索引是连续的,a后面肯定是b,非聚集索引就不连续了,就像图书馆的某个作者的书,有可能在第1个货架上和第10个货架上。还有一个小知识点就是:聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个。
1.2 索引的存储机制
首先,无索引的表,查询时,是按照顺序存续的方法扫描每个记录来查找符合条件的记录,这样效率十分低下,举个例子,如果我们将字典的汉字随即打乱,没有前面的按照拼音或者部首查询,那么我们想找一个字,按照顺序的方式去一页页的找,这样效率有多底,大家可以想象。
聚集索引和非聚集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致,其实理解起来非常简单,还是举字典的例子:如果按照拼音查询,那么都是从a-z的,是具有连续性的,a后面就是b,b后面就是c, 聚集索引就是这样的,他是和表的物理排列顺序是一样的,例如有id为聚集索引,那么1后面肯定是2,2后面肯定是3,所以说这样的搜索顺序的就是聚集索引。非聚集索引就和按照部首查询是一样是,可能按照偏房查询的时候,根据偏旁‘弓’字旁,索引出两个汉字,张和弘,但是这两个其实一个在100页,一个在1000页,(这里只是举个例子),他们的索引顺序和数据库表的排列顺序是不一样的,这个样的就是非聚集索引。
原理明白了,那他们是怎么存储的呢?在这里简单的说一下,聚集索引就是在数据库被开辟一个物理空间存放他的排列的值,例如1-100,所以当插入数据时,他会重新排列整个整个物理空间,而非聚集索引其实可以看作是一个含有聚集索引的表,他只仅包含原表中非聚集索引的列和指向实际物理表的指针。他只记录一个指针,其实就有点和堆栈差不多的感觉了
1.3 什么情况下设置索引
动作描述 | 使用聚集索引 | 使用非聚集索引 |
外键列 | 应 | 应 |
主键列 | 应 | 应 |
列经常被分组排序(order by) | 应 | 应 |
返回某范围内的数据 | 应 | 不应 |
小数目的不同值 | 应 | 不应 |
大数目的不同值 | 不应 | 应 |
频繁更新的列 | 不应 | 应 |
频繁修改索引列 | 不应 | 应 |
一个或极少不同值 | 不应 | 不应 |
建立索引的原则:
1) 定义主键的数据列一定要建立索引。
2) 定义有外键的数据列一定要建立索引。
3) 对于经常查询的数据列最好建立索引。
4) 对于需要在指定范围内的快速或频繁查询的数据列;
5) 经常用在WHERE子句中的数据列。
6) 经常出现在关键字order by、group by、distinct后面的字段,建立索引。如果建立的是复合索引,索引的字段顺序要和这些关键字后面的字段顺序一致,否则索引不会被使用。
7) 对于那些查询中很少涉及的列,重复值比较多的列不要建立索引。
8) 对于定义为text、image和bit的数据类型的列不要建立索引。
9) 对于经常存取的列避免建立索引
9) 限制表上的索引数目。对一个存在大量更新操作的表,所建索引的数目一般不要超过3个,最多不要超过5个。索引虽说提高了访问速度,但太多索引会影响数据的更新操作。
10) 对复合索引,按照字段在查询条件中出现的频度建立索引。在复合索引中,记录首先按照第一个字段排序。对于在第一个字段上取值相同的记录,系统再按照第二个字段的取值排序,以此类推。因此只有复合索引的第一个字段出现在查询条件中,该索引才可能被使用,因此将应用频度高的字段,放置在复合索引的前面,会使系统最大可能地使用此索引,发挥索引的作用。
1.4 如何创建索引
1.41 创建索引的语法:
CREATE [UNIQUE][CLUSTERED | NONCLUSTERED] INDEX index_name
ON {table_name | view_name} [WITH [index_property [,....n]]
说明:
UNIQUE: 建立唯一索引。
CLUSTERED: 建立聚集索引。
NONCLUSTERED: 建立非聚集索引。
Index_property: 索引属性。
UNIQUE索引既可以采用聚集索引结构,也可以采用非聚集索引的结构,如果不指明采用的索引结构,则SQL Server系统默认为采用非聚集索引结构。
1.42 删除索引语法:
DROP INDEX table_name.index_name[,table_name.index_name]
说明:table_name: 索引所在的表名称。
index_name : 要删除的索引名称。
1.43 显示索引信息:
使用系统存储过程:sp_helpindex 查看指定表的索引信息。
执行代码如下:
Exec sp_helpindex book1;
1.5 索引使用次数、索引效率、占用CPU检测、索引缺失
当我们明白了什么是索引,什么时间创建索引以后,我们就会想,我们创建的索引到底效率执行的怎么样?好不好?我们创建的对不对?
首先我们来认识一下DMV,DMV (dynamic management view)动态管理视图和函数返回特定于实现的内部状态数据。推出SQL Server 2005时,微软介绍了许多被称为dmvs的系统视图,让您可以探测SQL Server 的健康状况,诊断问题,或查看SQL Server实例的运行信息。统计数据是在SQL Server运行的时候开始收集的,并且在SQL Server每次启动的时候,统计数据将会被重置。当你删除或者重新创建其组件时,某些dmv的统计数据也可以被重置,例如存储过程和表,而其它的dmv信息在运行dbcc命令时也可以被重置。
当你使用一个dmv时,你需要紧记SQL Server收集这些信息有多长时间了,以确定这些从dmv返回的数据到底有多少可用性。如果SQL Server只运行了很短的一段时间,你可能不想去使用一些dmv统计数据,因为他们并不是一个能够代表SQL Server实例可能遇到的真实工作负载的样本。另一方面,SQL Server只能维持一定量的信息,有些信息在进行SQL Server性能管理活动的时候可能丢失,所以如果SQL Server已经运行了相当长的一段时间,一些统计数据就有可能已被覆盖。
因此,任何时候你使用dmv,当你查看从SQL Server 2005的dmvs返回的相关资料时,请务必将以上的观点装在脑海中。只有当你确信从dmvs获得的信息是准确和完整的,你才能变更数据库或者应用程序代码。
下面就看一下dmv到底能带给我们那些好的功能呢?
1.51 :索引使用次数
我们下看一下下面两种查询方式返回的结果(这两种查询的查询用途一致)
①----
declare @dbid int
select @dbid = db_id()
select objectname=object_name(s.object_id), s.object_id, indexname=i.name, i.index_id
, user_seeks, user_scans, user_lookups, user_updates
from sys.dm_db_index_usage_stats s,
sys.indexes i
where database_id = @dbid and objectproperty(s.object_id,‘IsUserTable‘) = 1
and i.object_id = s.object_id
and i.index_id = s.index_id
order by (user_seeks + user_scans + user_lookups + user_updates) asc
返回查询结果
②:使用多的索引排在前面
SELECT objects.name ,
databases.name ,
indexes.name ,
user_seeks ,
user_scans ,
user_lookups ,
partition_stats.row_count
FROM sys.dm_db_index_usage_stats stats
LEFT JOIN sys.objects objects ON stats.object_id = objects.object_id
LEFT JOIN sys.databases databases ON databases.database_id = stats.database_id
LEFT JOIN sys.indexes indexes ON indexes.index_id = stats.index_id
AND stats.object_id = indexes.object_id
LEFT JOIN sys.dm_db_partition_stats partition_stats ON stats.object_id = partition_stats.object_id
AND indexes.index_id = partition_stats.index_id
WHERE 1 = 1
--AND databases.database_id = 7
AND objects.name IS NOT NULL
AND indexes.name IS NOT NULL
AND user_scans>0
ORDER BY user_scans DESC ,
stats.object_id ,
indexes.index_id
返回查询结果
user_seeks : 通过用户查询执行的搜索次数。
个人理解: 此统计索引搜索的次数
user_scans: 通过用户查询执行的扫描次数。
个人理解:此统计表扫描的次数,无索引配合
user_lookups: 通过用户查询执行的查找次数。
个人理解:用户通过索引查找,在使用RID或聚集索引查找数据的次数,对于堆表或聚集表数据而言和索引配合使用次数
user_updates: 通过用户查询执行的更新次数。
个人理解:索引或表的更新次数
我们可以清晰的看到,那些索引用的多,那些索引没用过,大家可以根据查询出来的东西去分析自己的数据索引和表
1.52 :索引提高了多少性能
新建了索引到底增加了多少数据的效率呢?到底提高了多少性能呢?运行如下SQL可以返回连接缺失索引动态管理视图,发现最有用的索引和创建索引的方法:
SELECT
avg_user_impact AS average_improvement_percentage,
avg_total_user_cost AS average_cost_of_query_without_missing_index,
‘CREATE INDEX ix_‘ + [statement] +
ISNULL(equality_columns, ‘_‘) +
ISNULL(inequality_columns, ‘_‘) + ‘ ON ‘ + [statement] +
‘ (‘ + ISNULL(equality_columns, ‘ ‘) +
ISNULL(inequality_columns, ‘ ‘) + ‘)‘ +
ISNULL(‘ INCLUDE (‘ + included_columns + ‘)‘, ‘‘)
AS create_missing_index_command
FROM sys.dm_db_missing_index_details a INNER JOIN
sys.dm_db_missing_index_groups b ON a.index_handle = b.index_handle
INNER JOIN sys.dm_db_missing_index_group_stats c ON
b.index_group_handle = c.group_handle
WHERE avg_user_impact > = 40
返回结果
虽然用户能够修改性能提高的百分比,但以上查询返回所有能够将性能提高40%或更高的索引。你可以清晰的看到每个索引提高的性能和效率了
1.53 :最占用CPU、执行时间最长命令
这个和索引无关,但是还是在这里提出来,因为他也属于DMV带给我们的功能吗,他可以让你轻松查询出,那些sql语句占用你的cpu最高
SELECT TOP 100 execution_count,
total_logical_reads /execution_count AS [Avg Logical Reads],
total_elapsed_time /execution_count AS [Avg Elapsed Time],
db_name(st.dbid) as [database name],
object_name(st.dbid) as [object name],
object_name(st.objectid) as [object name 1],
SUBSTRING(st.text, (qs.statement_start_offset / 2) + 1,
((CASE statement_end_offset WHEN - 1 THEN DATALENGTH(st.text) ELSE qs.statement_end_offset END - qs.statement_start_offset)
/ 2) + 1) AS statement_text
FROM sys.dm_exec_query_stats AS qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
WHERE execution_count > 100
ORDER BY 1 DESC;
返回结果:
执行时间最长的命令
SELECT TOP 10 COALESCE(DB_NAME(st.dbid),
DB_NAME(CAST(pa.value as int))+‘*‘,
‘Resource‘) AS DBNAME,
SUBSTRING(text,
-- starting value for substring
CASE WHEN statement_start_offset = 0
OR statement_start_offset IS NULL
THEN 1
ELSE statement_start_offset/2 + 1 END,
-- ending value for substring
CASE WHEN statement_end_offset = 0
OR statement_end_offset = -1
OR statement_end_offset IS NULL
THEN LEN(text)
ELSE statement_end_offset/2 END -
CASE WHEN statement_start_offset = 0
OR statement_start_offset IS NULL
THEN 1
ELSE statement_start_offset/2 END + 1
) AS TSQL,
total_logical_reads/execution_count AS AVG_LOGICAL_READS
FROM sys.dm_exec_query_stats
CROSS APPLY sys.dm_exec_sql_text(sql_handle) st
OUTER APPLY sys.dm_exec_plan_attributes(plan_handle) pa
WHERE attribute = ‘dbid‘
ORDER BY AVG_LOGICAL_READS DESC ;
看到了吗?直接可以定位到你的sql语句,优化去吧。还等什么呢?
1.54:缺失索引
缺失索引就是帮你查找你的数据库缺少什么索引,告诉你那些字段需要加上索引,这样你就可以根据提示添加你数据库缺少的索引了
SELECT TOP 10
[Total Cost] = ROUND(avg_total_user_cost * avg_user_impact * (user_seeks + user_scans),0)
, avg_user_impact
, TableName = statement
, [EqualityUsage] = equality_columns
, [InequalityUsage] = inequality_columns
, [Include Cloumns] = included_columns
FROM sys.dm_db_missing_index_groups g
INNER JOIN sys.dm_db_missing_index_group_stats s
ON s.group_handle = g.index_group_handle
INNER JOIN sys.dm_db_missing_index_details d
ON d.index_handle = g.index_handle
ORDER BY [Total Cost] DESC;
查询结果如下:
1.6 适当创建索引覆盖
假设你在Sales表(SelesID,SalesDate,SalesPersonID,ProductID,Qty)的外键列(ProductID)上创建了一个索引,假设ProductID列是一个高选中性列,那么任何在where子句中使用索引列(ProductID)的select查询都会更快,如果在外键上没有创建索引,将会发生全部扫描,但还有办法可以进一步提升查询性能。
假设Sales表有10,000行记录,下面的SQL语句选中400行(总行数的4%):
SELECT SalesDate, SalesPersonID FROM Sales WHERE ProductID = 112
我们来看看这条SQL语句在SQL执行引擎中是如何执行的:
1)Sales表在ProductID列上有一个非聚集索引,因此它查找非聚集索引树找出ProductID=112的记录;
2)包含ProductID = 112记录的索引页也包括所有的聚集索引键(所有的主键键值,即SalesID);
3)针对每一个主键(这里是400),SQL Server引擎查找聚集索引树找出真实的行在对应页面中的位置;
SQL Server引擎从对应的行查找SalesDate和SalesPersonID列的值。
在上面的步骤中,对ProductID = 112的每个主键记录(这里是400),SQL Server引擎要搜索400次聚集索引树以检索查询中指定的其它列(SalesDate,SalesPersonID)。
如果非聚集索引页中包括了聚集索引键和其它两列(SalesDate,,SalesPersonID)的值,SQL Server引擎可能不会执行上面的第3和4步,直接从非聚集索引树查找ProductID列速度还会快一些,直接从索引页读取这三列的数值。
幸运的是,有一种方法实现了这个功能,它被称为“覆盖索引”,在表列上创建覆盖索引时,需要指定哪些额外的列值需要和聚集索引键值(主键)一起存储在索引页中。下面是在Sales 表ProductID列上创建覆盖索引的例子:
CREATE INDEX NCLIX_Sales_ProductID--Index name
ON dbo.Sales(ProductID)--Column on which index is to be created
INCLUDE(SalesDate, SalesPersonID)--Additional column values to include
应该在那些select查询中常使用到的列上创建覆盖索引,但覆盖索引中包括过多的列也不行,因为覆盖索引列的值是存储在内存中的,这样会消耗过多内存,引发性能下降。
1.7 索引碎片
在数据库性能优化一:数据库自身优化一文中已经讲到了这个问题,再次就不做过多的重复地址:http://www.cnblogs.com/AK2012/archive/2012/12/25/2012-1228.html
1.8 索引实战(摘抄)
之所以这章摘抄,是因为下面这个文章已经写的太好了,估计我写出来也无法比这个好了,所以就摘抄了
人们在使用SQL时往往会陷入一个误区,即太关注于所得的结果是否正确,而忽略了不同的实现方法之间可能存在的性能差异,这种性能差异在大型的或是复杂的数据库环境中(如联机事务处理OLTP或决策支持系统DSS)中表现得尤为明显。
笔者在工作实践中发现,不良的SQL往往来自于不恰当的索引设计、不充份的连接条件和不可优化的where子句。
在对它们进行适当的优化后,其运行速度有了明显地提高!
下面我将从这三个方面分别进行总结:
为了更直观地说明问题,所有实例中的SQL运行时间均经过测试,不超过1秒的均表示为(< 1秒)。----
测试环境: 主机:HP LH II---- 主频:330MHZ---- 内存:128兆----
操作系统:Operserver5.0.4----
数据库:Sybase11.0.3
一、不合理的索引设计----
例:表record有620000行,试看在不同的索引下,下面几个 SQL的运行情况:
---- 1.在date上建有一非个群集索引
select count(*) from record where date >‘19991201‘ and date < ‘19991214‘and amount >2000 (25秒)
select date ,sum(amount) from record group by date(55秒)
select count(*) from record where date >‘19990901‘ and place in (‘BJ‘,‘SH‘) (27秒)
---- 分析:----
date上有大量的重复值,在非群集索引下,数据在物理上随机存放在数据页上,在范围查找时,必须执行一次表扫描才能找到这一范围内的全部行。
---- 2.在date上的一个群集索引
select count(*) from record where date >‘19991201‘ and date < ‘19991214‘ and amount >2000 (14秒)
select date,sum(amount) from record group by date(28秒)
select count(*) from record where date >‘19990901‘ and place in (‘BJ‘,‘SH‘)(14秒)
---- 分析:---- 在群集索引下,数据在物理上按顺序在数据页上,重复值也排列在一起,因而在范围查找时,可以先找到这个范围的起末点,且只在这个范围内扫描数据页,避免了大范围扫描,提高了查询速度。
---- 3.在place,date,amount上的组合索引
select count(*) from record where date >‘19991201‘ and date < ‘19991214‘ and amount >2000 (26秒)
select date,sum(amount) from record group by date(27秒)
select count(*) from record where date >‘19990901‘ and place in (‘BJ, ‘SH‘)(< 1秒)
---- 分析:---- 这是一个不很合理的组合索引,因为它的前导列是place,第一和第二条SQL没有引用place,因此也没有利用上索引;第三个SQL使用了place,且引用的所有列都包含在组合索引中,形成了索引覆盖,所以它的速度是非常快的。
---- 4.在date,place,amount上的组合索引
select count(*) from record where date >‘19991201‘ and date < ‘19991214‘ and amount >2000(< 1秒)
select date,sum(amount) from record group by date(11秒)
select count(*) from record where date >‘19990901‘ and place in (‘BJ‘,‘SH‘)(< 1秒)
---- 分析:---- 这是一个合理的组合索引。它将date作为前导列,使每个SQL都可以利用索引,并且在第一和第三个SQL中形成了索引覆盖,因而性能达到了最优。
---- 5.总结:----
缺省情况下建立的索引是非群集索引,但有时它并不是最佳的;合理的索引设计要建立在对各种查询的分析和预测上。
一般来说:
①.有大量重复值、且经常有范围查询(between, >,< ,>=,< =)和order by、group by发生的列,可考虑建立群集索引;
②.经常同时存取多列,且每列都含有重复值可考虑建立组合索引;
③.组合索引要尽量使关键查询形成索引覆盖,其前导列一定是使用最频繁的列。
二、不充份的连接条件:
例:表card有7896行,在card_no上有一个非聚集索引,表account有191122行,在account_no上有一个非聚集索引,试看在不同的表连接条件下,两个SQL的执行情况:
select sum(a.amount) from account a,card b where a.card_no = b.card_no(20秒)
select sum(a.amount) from account a,card b where a.card_no = b.card_no and a.account_no=b.account_no(< 1秒)
---- 分析:---- 在第一个连接条件下,最佳查询方案是将account作外层表,card作内层表,利用card上的索引,其I/O次数可由以下公式估算为:
外层表account上的22541页+(外层表account的191122行*内层表card上对应外层表第一行所要查找的3页)=595907次I/O
在第二个连接条件下,最佳查询方案是将card作外层表,account作内层表,利用account上的索引,其I/O次数可由以下公式估算为:外层表card上的1944页+(外层表card的7896行*内层表account上对应外层表每一行所要查找的4页)= 33528次I/O
可见,只有充份的连接条件,真正的最佳方案才会被执行。
总结:
1.多表操作在被实际执行前,查询优化器会根据连接条件,列出几组可能的连接方案并从中找出系统开销最小的最佳方案。连接条件要充份考虑带有索引的表、行数多的表;内外表的选择可由公式:外层表中的匹配行数*内层表中每一次查找的次数确定,乘积最小为最佳方案。
2.查看执行方案的方法-- 用set showplanon,打开showplan选项,就可以看到连接顺序、使用何种索引的信息;想看更详细的信息,需用sa角色执行dbcc(3604,310,302)。
三、不可优化的where子句
1.例:下列SQL条件语句中的列都建有恰当的索引,但执行速度却非常慢:
select * from record wheresubstring(card_no,1,4)=‘5378‘(13秒)
select * from record whereamount/30< 1000(11秒)
select * from record whereconvert(char(10),date,112)=‘19991201‘(10秒)
分析:
where子句中对列的任何操作结果都是在SQL运行时逐列计算得到的,因此它不得不进行表搜索,而没有使用该列上面的索引;
如果这些结果在查询编译时就能得到,那么就可以被SQL优化器优化,使用索引,避免表搜索,因此将SQL重写成下面这样:
select * from record where card_no like‘5378%‘(< 1秒)
select * from record where amount< 1000*30(< 1秒)
select * from record where date= ‘1999/12/01‘(< 1秒)
你会发现SQL明显快起来!
2.例:表stuff有200000行,id_no上有非群集索引,请看下面这个SQL:
select count(*) from stuff where id_no in(‘0‘,‘1‘)(23秒)
分析:---- where条件中的‘in‘在逻辑上相当于‘or‘,所以语法分析器会将in (‘0‘,‘1‘)转化为id_no =‘0‘ or id_no=‘1‘来执行。
我们期望它会根据每个or子句分别查找,再将结果相加,这样可以利用id_no上的索引;
但实际上(根据showplan),它却采用了"OR策略",即先取出满足每个or子句的行,存入临时数据库的工作表中,再建立唯一索引以去掉重复行,最后从这个临时表中计算结果。因此,实际过程没有利用id_no上索引,并且完成时间还要受tempdb数据库性能的影响。
实践证明,表的行数越多,工作表的性能就越差,当stuff有620000行时,执行时间竟达到220秒!还不如将or子句分开:
select count(*) from stuff where id_no=‘0‘select count(*) from stuff where id_no=‘1‘
得到两个结果,再作一次加法合算。因为每句都使用了索引,执行时间只有3秒,在620000行下,时间也只有4秒。
或者,用更好的方法,写一个简单的存储过程:
create proc count_stuff asdeclare @a intdeclare @b intdeclare @c intdeclare @d char(10)beginselect @a=count(*) from stuff where id_no=‘0‘select @b=count(*) from stuff where id_no=‘1‘endselect @c=@a+@bselect @d=convert(char(10),@c)print @d
直接算出结果,执行时间同上面一样快!
---- 总结:---- 可见,所谓优化即where子句利用了索引,不可优化即发生了表扫描或额外开销。
1.任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。
2.in、or子句常会使用工作表,使索引失效;如果不产生大量重复值,可以考虑把子句拆开;拆开的子句中应该包含索引。
3.要善于使用存储过程,它使SQL变得更加灵活和高效。
从以上这些例子可以看出,SQL优化的实质就是在结果正确的前提下,用优化器可以识别的语句,充份利用索引,减少表扫描的I/O次数,尽量避免表搜索的发生。其实SQL的性能优化是一个复杂的过程,上述这些只是在应用层次的一种体现,深入研究还会涉及数据库层的资源配置、网络层的流量控制以及操作系统层的总体设计。
1.7索引实战是摘抄网友的文章,引用地址:http://blog.csdn.net/gprime/article/details/1687930
SQL索引
标签:
sql server 2008 中如何建立索引
都一样的吧
用 SQL 语句的话,比方:
CREATE ( CLUSTERED ) INDEX [index-name] ON [table-name] (column list);
sqlserver2008创建索引,如下的查询语句,where条件中需要创建复合的索引好还是逐个的单个创建,效果如何
复合索引一般要求索引中的列全部为where筛选条件,并且一定要按顺序写
如果你这几个条件确实是经常一起用,可以创建复合索引,并且把最最常用的那个列设为首项