在SQLServer中使用索引的技巧

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在SQLServer中使用索引的技巧相关的知识,希望对你有一定的参考价值。

参考技术A

  在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 )

lishixinzhi/Article/program/SQLServer/201311/22210

sqlserver索引

索引概念

 索引是与视图关联的磁盘或内存中结构,可以加快从表或视图中的检索速度。索引包含由表或视图中的一列或多列生成的键。

索引特点

  • 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。  
  • 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
  • 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。  
  • 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
  • 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。  

索引不足

  • 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。  
  • 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
  • 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。  

应该建立索引的特点 

  • 在经常需要搜索的列上,可以加快搜索的速度;
  • 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
  • 在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
  • 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
  • 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
  • 在经常使用在 WHERE 子句中的列上面创建索引,加快条件的判断速度。

不应该建立索引的特点

  • 对于那些在查询中很少使用或者参考的列不应该创建索引。这是因为,既然这些列很 少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降 低了系统的维护速度和增大了空间需求。
  • 对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少, 例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需 要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
  • 对于那些定义为 blob 数据类型的列不应该增加索引。这是因为,这些列的数据量要 么相当大,要么取值很少。
  • 当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能 是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会 提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。

聚集索引和非聚集索引

聚集索引和非聚集索引都可以是唯一的。 这意味着任何两行都不能有相同的索引键值。 

聚集索引:聚集索引根据数据行的键值在表或视图中排序和存储这些数据行。 索引定义中包含聚集索引列。 每个表只能有一个聚集索引,因为数据行本身只能按一个顺序存储。

非聚集索引:

  非聚集索引具有独立于数据行的结构。 非聚集索引包含非聚集索引键值,并且每个键值项都有指向包含该键值的数据行的指针。

  从非聚集索引中的索引行指向数据行的指针称为行定位器。 行定位器的结构取决于数据页是存储在堆中还是聚集表中。 

在表中创建主键约束和唯一约束会自动创建索引,创建主键约束时会自动创建聚集索引;创建唯一约束索引会自动创建非聚集索引。

--创建表时添加约束
CREATE TABLE Production.TransactionHistoryArchive1 ( 
  TransactionID int IDENTITY (1,1) PRIMARY KEY NOT NULL
); 
CREATE TABLE Production.TransactionHistoryArchive1 ( 
  TransactionID int IDENTITY (1,1) NOT NULL, 
  CONSTRAINT PK_TransactionHistoryArchive_TransactionID PRIMARY KEY CLUSTERED (TransactionID) 
); 

--主键
alter table abo.tableName Add constraint pk_name primary key
--唯一约束
alter table Account add constraint AK_AccountName unique (Account_Name) 
--删除约束
alter table AdItem drop constraint AdOrder_AdItem_FK1

聚集索引

在 SQL Server 中,索引是按 B 树结构组织的。 索引 B 树中的每一页称为一个索引节点。 B 树的顶端节点称为根节点。 索引中的底层节点称为叶节点。 根节点与叶节点之间的任何索引级别统称为中间级。 在聚集索引中,叶节点包含基础表的数据页。 根节点和中间级节点包含存有索引行的索引页。每个索引行包含一个键值和一个指针,该指针指向 B 树上的某一中间级页或叶级索引中的某个数据行。 每级索引中的页均被链接在双向链接列表中。

聚集索引在 sys.partitions中有一行,其中,索引使用的每个分区的 index_id = 1。 默认情况下,聚集索引有单个分区。 当聚集索引有多个分区时,每个分区都有一个包含该特定分区相关数据的 B 树结构。 例如,如果聚集索引有四个分区,就有四个 B 树结构,每个分区中有一个 B 树结构。

根据聚集索引中的数据类型,每个聚集索引结构将有一个或多个分配单元,将在这些单元中存储和管理特定分区的相关数据。 每个聚集索引的每个分区中至少有一个 IN_ROW_DATA 分配单元。 如果聚集索引包含大型对象 (LOB) 列,则它的每个分区中还会有一个 LOB_DATA 分配单元。 如果聚集索引包含的变量长度列超过 8,060 字节的行大小限制,则它的每个分区中还会有一个 ROW_OVERFLOW_DATA 分配单元。

数据链内的页和行将按聚集索引键值进行排序。 所有插入操作都在所插入行中的键值与现有行中的排序顺序相匹配时执行。

下图显式了聚集索引单个分区中的结构。

   

    技术图片

  建议使用聚集索引事项

  1.   使用运算符(如 BETWEEN、>、>=、< 和 <=)返回一系列值
  2.   返回大型结果集
  3.   使用 JOIN 子句;一般情况下,使用该子句的是外键列。
  4.   使用 ORDER BY 或 GROUP BY 子句

  注:定义聚集索引键时使用的列越少越好

  什么情况下不适合创建聚集索引

  频繁更改的列

  宽键(组合聚集索引,选择的列太多)

非聚集索引

非聚集索引包含索引键值和指向表数据存储位置的行定位器。 可以对表或索引视图创建多个非聚集索引。 通常,设计非聚集索引是为改善经常使用的、没有建立聚集索引的查询的性能。

与使用书中索引的方式相似,查询优化器在搜索数据值时,先搜索非聚集索引以找到数据值在表中的位置,然后直接从该位置检索数据。 这使非聚集索引成为完全匹配查询的最佳选择,因为索引包含说明查询所搜索的数据值在表中的精确位置的项。 例如,为了从 HumanResources. Employee 表中查询向特定经理负责的所有雇员,查询优化器可能使用非聚集索引 IX_Employee_ManagerID;它以 ManagerID 作为其键列。 查询优化器能快速找出索引中与指定 ManagerID匹配的所有项。 每个索引项都指向表或聚集索引中准确的页和行,其中可以找到相应的数据。 在查询优化器在索引中找到所有项之后,它可以直接转到准确的页和行进行数据检索。

  非聚集索引体系结构

  非聚集索引与聚集索引具有相同的 B 树结构,它们之间的显著差别在于以下两点:

  •   基础表的数据行不按非聚集键的顺序排序和存储。
  •   非聚集索引的叶级别是由索引页而不是由数据页组成。

  非聚集索引行中的行定位器或是指向行的指针,或是行的聚集索引键,如下所述:

  •   如果表是堆(意味着该表没有聚集索引),则行定位器是指向行的指针。 该指针由文件标识符 (ID)、页码和页上的行数生成。 整个指针称为行 ID (RID)。
  •   如果表有聚集索引或索引视图上有聚集索引,则行定位器是行的聚集索引键。

对于索引使用的每个分区,非聚集索引在 index_id >1 的 sys.partitions 中都有对应的一行。 默认情况下,一个非聚集索引有单个分区。 如果一个非聚集索引有多个分区,则每个分区都有一个包含该特定分区的索引行的 B 树结构。 例如,如果一个非聚集索引有四个分区,那么就有四个 B 树结构,每个分区中一个。

根据非聚集索引中数据类型的不同,每个非聚集索引结构会有一个或多个分配单元,在其中存储和管理特定分区的数据。 每个非聚集索引至少有一个针对每个分区的 IN_ROW_DATA 分配单元(存储索引 B 树页)。 如果非聚集索引包含大型对象 (LOB) 列,则还有一个针对每个分区的 LOB_DATA 分配单元。 此外,如果非聚集索引包含的可变长度列超过 8,060 字节的行大小限制,则还有一个针对每个分区的 ROW_OVERFLOW_DATA 分配单元。

下图说明了单个分区中的非聚集索引结构。

技术图片

建议使用非聚集索引事项

  1.   使用 JOIN 或 GROUP BY 子句
  2.   不返回大型结果集的查询
  3.   包含经常包含在查询的搜索条件(例如返回完全匹配的 WHERE 子句)中的列
  4.   覆盖查询 (当索引包含查询中的所有列时,性能可以提升。)
  5.   大量非重复值,如姓氏和名字的组合(前提是聚集索引被用于其他列)

  带有包含列的索引准则

  1.   在 CREATE INDEX 语句的 INCLUDE 子句中定义非键列
  2.   只能对表或索引视图的非聚集索引定义非键列
  3.   允许除 text、 ntext和 image之外的所有数据类型
  4.   精确或不精确的确定性计算列都可以是包含列
  5.   与键列一样,只要允许将计算列数据类型作为非键索引列,从 image、 ntext和 text 数据类型派生的计算列就可以作为非键(包含性)列。
  6.   不能同时在 INCLUDE 列表和键列列表中指定列名。
  7.   INCLUDE 列表中的列名不能重复

唯一索引和筛选索引

唯一索引能够保证索引键中不包含重复的值,从而使表中的每一行从某种方式上具有唯一性。

筛选索引是一种经过优化的非聚集索引,尤其适用于涵盖从定义完善的数据子集中选择数据的查询。筛选索引使用筛选谓词对表中的部分行进行索引。用于重复性比较高的列

索引创建

CREATE [UNIQUE] [CLUSTERED| NONCLUSTERED ]
INDEX index_name ON { table | view } ( column [ ASC | DESC ] [ ,...n ] )
[with[PAD_INDEX][[,]FILLFACTOR=fillfactor]
[[,]IGNORE_DUP_KEY]
[[,]DROP_EXISTING]
[[,]STATISTICS_NORECOMPUTE]
[[,]SORT_IN_TEMPDB]
]
[ ON filegroup ]   

--ag:
CREATE TABLE dbo.TestTable  
    (TestCol1 int NOT NULL,  
     TestCol2 nchar(10) NULL,  
     TestCol3 nvarchar(50) NULL);  
GO  
CREATE CLUSTERED INDEX IX_TestTable_TestCol1   
    ON dbo.TestTable (TestCol1); 

索引的限制

 

 1、使用不等于操作符(<>、 !=)  

 

select cust_Id,cust_name from customers where cust_rating <> ‘aa‘;
--正确写法
select cust_Id,cust_name from customers where cust_rating < ‘aa‘ or cust_rating > ‘aa‘;

 

 2、使用 IS NULL 或 IS NOT NULL

 

使用 IS NULL 或 IS NOT NULL 同样会限制索引的使用。因为 NULL 值并没有被定义。
在 SQL 语句中使用 NULL 会有很多的麻烦。因此建议开发人员在建表时,把需要索引的列设成 NOT NULL。
如果被索引的列在某些行中存在 NULL 值,就不会使用这个索引

 

 3、使用函数   

 

--account_number 是字符类型
select bank_name,address,city,state,zip from banks where account_number = 990354; 
--正确写法
select bank_name,address,city,state,zip from banks where account_number =‘990354‘; 

 

 

 

资料: 索引体系结构和设计 聚集索引和非聚集索引 

     SqlServer索引的原理与应用  

    SQLSERVER聚集索引与非聚集索引的再次研究(上)

     SQLSERVER聚集索引与非聚集索引的再次研究(下)

     

 

 

 

 

以上是关于在SQLServer中使用索引的技巧的主要内容,如果未能解决你的问题,请参考以下文章

org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class 'com.microsoft.sqlserv

DataX SqlServerWriter手册参数

使用 SQL Server 进行性能调优

sQL server 啥是实例?

拆分数据库的技巧

使用索引的技巧