sqlserver 索引的一些总结_MsSql

1.1.1 摘要
如果说要对数据库进行优化我们主要可以通过以下五种方法对数据库系统进行优化。

1. 计算机硬件调优
2. 应用程序调优
3. 数据库索引优化
4. SQL语句优化
5. 事务处理调优

在本篇博文中我们将想大家讲述数据库中索引类型和使用场合本文以SQL Server为例对于其他技术平台的朋友也是有参考价值的只要替换相对应的代码就行了

索引使数据库引擎执行速度更快有针对性的数据检索而不是简单地整表扫描Full table scan。

为了使用有效的索引我们必须对索引的构成有所了解而且我们知道在数据表中添加索引必然需要创建和维护索引表所以我们要全局地衡量添加索引是否能提高数据库系统的查询性能。

在物理层面上数据库有数据文件组成而这些数据文件可以组成文件组然后存储在磁盘上。每个文件包含许多区每个区的大小为64K由八个物理上连续的页组成一个页8K我们知道页是SQL Server数据库中的数据存储的基本单位。为数据库中的数据文件.mdf 或 .ndf分配的磁盘空间可以从逻辑上划分成页从0到n连续编号。

页中存储的类型有数据索引和溢出。

文件和文件组
在SQL Server中通过文件组这个逻辑对象对存放数据的文件进行管理。

1.1.2 正文

在物理层面上数据库有数据文件组成而这些数据文件可以组成文件组然后存储在磁盘上。每个文件包含许多区每个区的大小为64K由八个物理上连续的页组成一个页8K我们知道页是SQL Server数据库中的数据存储的基本单位。为数据库中的数据文件.mdf 或 .ndf分配的磁盘空间可以从逻辑上划分成页从0到n连续编号。

页中存储的类型有数据索引和溢出。

文件和文件组
在SQL Server中通过文件组这个逻辑对象对存放数据的文件进行管理。

图1数据库文件组织

在顶层是我们的数据库由于数据库是由一个或多个文件组组成而文件组是由一个或多个文件组成的​​逻辑组所以我们可以把文件组分散到不同的磁盘中使用户数据尽可能跨越多个设备多个I/O 运转避免 I/O 竞争从而均衡I/O负载克服访问瓶颈。

区和页
如图2所示文件是由区组成的而区由八个物理上连续的页组成由于区的大小为64K所以每当增加一个区文件就增加64K。

图2文件组成

页中保存的数据类型有表数据、索引数据、溢出数据、分配映射、页空闲空间、索引分配等具体如下图所示


页类型


内容


Data


当 text in row 设置为 ON 时包含除 text、 ntext、image、nvarchar(max)、varchar(max)、varbinary(max) 和 xml 数据之外的所有数据的数据行。


Index


索引条目。


Text/Image


大型对象数据类型text 、 ntext、image、nvarchar(max)、varchar(max)、varbinary(max) 和 xml 数据。数据行超过 8 KB 时为可变长度数据类型列varchar 、nvarchar、varbinary 和 sql_variant


Global Allocation Map、Shared Global Allocation Map


有关区是否分配的信息。


Page Free Space


有关页分配和页的可用空间的信息。


Index Allocation Map


有关每个分配单元中表或索引所使用的区的信息。


Bulk Changed Map


有关每个分配单元中自最后一条 BACKUP LOG 语句之后的大容量操作所修改的区的信息。


Differential Changed Map


有关每个分配单元中自最后一条 BACKUP DATABASE 语句之后更改的区的信息。

表1页中保存的数据类型

在数据页上数据行紧接着页头标头按顺序放置页头包含标识值如页码或对象数据的对象ID数据行持有实际的数据最后页的末尾是行偏移表对于页中的每一行每个行偏移表都包含一个条目每个条目记录对应行的第一个字节与页头的距离行偏移表中的条目的顺序与页中行的顺序相反。

图3数据页

索引的基本结构
“索引Index提供查询的速度”这是对索引的最基本的解释接下来我们将通过介绍索引的组成让大家对索引有更深入的理解。

索引是数据库中的一个独特的结构由于它保存数据库信息那么我们就需要给它分配磁盘空间和维护索引表。创建索引并不会改变表中的数据它只是创建了一个新的数据结构指向数据表打个比方平时我们使用字典查字时首先我们要知道查询单词起始字母然后翻到目录页接着查找单词具体在哪一页这时我们目录就是索引表而目录项就是索引了。

当然索引比字典目录更为复杂因为数据库必须处理插入删除和更新等操作这些操作将导致索引发生变化。

叶节点

假设我们磁盘上的数据是物理有序的那么数据库在进行插入删除和更新操作时必然会导致数据发生变化如果我们要保存数据的连续和有序那么我们就需要移动数据的物理位置这将增大磁盘的I/O使得整个数据库运行非常缓慢使用索引的主要目的是使数据逻辑有序使数据独立于物理有序存储。

为了实现数据逻辑有序索引使用双向链表的数据结构来保持数据逻辑顺序如果要在两个节点中插入一个新的节点只需修改节点的前驱和后继而且无需修改新节点的物理位置。

双向链表Doubly linked list也叫双链表是链表的一种它的每个数据结点中都有两个指针分别指向直接后继和直接前驱。所以从双向链表中的任意一个结点开始都可以很方便地访问它的前驱结点和后继结点。

理论上说从双向链表中删除一个元素操作的时间复杂度是O(1)如果希望删除一个具体有给定关键字的元素那么最坏的情况下的时间复杂度为O(n)。

在删除的过程中我们只需要将要删除的节点的前节点和后节点相连然后将要删除的节点的前节点和后节点置为null即可。

复制代码 代码如下:

//伪代码
node.prev.next=node.next;
node.next.prev=node.prev;
node.prev=node.next=null;


图4索引的叶节点和相应的表数据

如上图4所示索引叶节点包含索引值和相应的RIDROWID而且叶节点通过双向链表有序地连接起来同时我们主要到数据表不同于索引叶节点表中的数据无序存储它们不全是存储在同一表块中而且块之间不存在连接。

总的来说索引保存着具体数据的物理地址值。

索引的类型

我们知道索引的类型有两种聚集索引和非聚集索引。
聚集索引物理存储按照索引排序。
非聚集索引物理存储不按照索引排序。

聚集索引

聚集索引的数据页是物理有序地存储数据页是聚集索引的叶节点数据页之间通过双向链表的形式连接起来而且实际的数据都存储在数据页中。当我们给表添加索引后表中的数据将根据索引进行排序。
假设我们有一个表T_Pet它包含四个字段分别是animalnamesex和age而且使用animal作为索引列具体SQL代码如下

复制代码 代码如下:

-----------------------------------------------------------
---- Create T_Pet table in tempdb.
-----------------------------------------------------------
USE tempdb
CREATE TABLE T_Pet
(
animal VARCHAR(20),
[name] VARCHAR(20),
sex CHAR(1),
age INT
)
CREATE UNIQUE CLUSTERED INDEX T_PetonAnimal1_ClterIdx ON T_Pet (animal)

-----------------------------------------------------------
---- Insert data into data table.
-----------------------------------------------------------

复制代码 代码如下:

DECLARE @i int
SET @i=0
WHILE(@i<1000000)
BEGIN
INSERT INTO T_Pet (
animal,
[name],
sex,
age
)
SELECT [dbo].random_string(11) animal,
[dbo].random_string(11) [name],
'F' sex,
cast(floor(rand()*5) as int) age
SET @i=@i+1
END
INSERT INTO T_Pet VALUES('Aardark', 'Hello', 'F', 1)
INSERT INTO T_Pet VALUES('Cat', 'Kitty', 'F', 2)
INSERT INTO T_Pet VALUES('Horse', 'Ma', 'F', 1)
INSERT INTO T_Pet VALUES('Turtles', 'SiSi', 'F', 4)
INSERT INTO T_Pet VALUES('Dog', 'Tomma', 'F', 2)
INSERT INTO T_Pet VALUES('Donkey', 'YoYo', 'F', 3)


图5聚集索引

如上图5所示从左往右的第一和第二层是索引页第三层是数据页叶节点数据页之间通过双向链表连接起来而且数据页中的数据根据索引排序假设我们要查找名字name为Xnnbqba的动物Ifcey这里我们以animal作为表的索引所以数据库首先根据索引查找当找到索引值animal = ‘Ifcey时接着查找该索引的数据页叶节点获取具体数据。具体的查询语句如下

复制代码 代码如下:

SET STATISTICS PROFILE ON
SET STATISTICS TIME ON

SELECT animal, [name], sex, age
FROM T_Pet
WHERE animal = 'Ifcey'

SET STATISTICS PROFILE OFF
SET STATISTICS TIME OFF

当我们执行完SQL查询计划时把鼠标指针放到“聚集索引查找”上这时会出现如下图信息我们可以查看到一个重要的信息Logical Operation——Clustered Index SeekSQL查询是直接根据聚集索引获取记录查询速度最快。

图6查询计划

从下图查询结果我们发现查询步骤只有2步首先通过Clustered Index Seek快速地找到索引Ifcey接着查询索引的叶节点数据页获取数据。

查询执行时间CPU 时间= 0 毫秒占用时间= 1 毫秒。

图7查询结果

现在我们把表中的索引删除重新执行查询计划这时我们可以发现Logical Operation已经变为Table Scan由于表中有100万行数据这时查询速度就相当缓慢。 

图8查询计划

从下图查询结果我们发现查询步骤变成3步了首先通过Table Scan查找animal = ‘Ifcey'在执行查询的时候SQL Server会自动分析SQL语句而且它估计我们这次查询比较耗时所以数据库进行并发操作加快查询的速度。

查询执行时间CPU 时间= 329 毫秒占用时间= 182 毫秒。 

图9查询结果

通过上面的有聚集索引和没有的对比我们发现了查询性能的差异如果使用索引数据库首先查找索引而不是漫无目的的全表遍历。

非聚集索引

在没有聚集索引的情况下表中的数据页是通过堆(Heap)形式进行存储堆是不含聚集索引的表SQL Server中的堆存储是把新的数据行存储到最后一个页中。

非聚集索引是物理存储不按照索引排序非聚集索引的叶节点Index leaf pages包含着指向具体数据行的指针或聚集索引数据页之间没有连接是相对独立的页。

假设我们有一个表T_Pet它包含四个字段分别是animalnamesex和age而且使用animal作为非索引列具体SQL代码如下

复制代码 代码如下:

-----------------------------------------------------------
---- Create T_Pet table in tempdb with NONCLUSTERED INDEX.
-----------------------------------------------------------
USE tempdb
CREATE TABLE T_Pet
(
animal VARCHAR(20),
[name] VARCHAR(20),
sex CHAR(1),
age INT
)
CREATE UNIQUE NONCLUSTERED INDEX T_PetonAnimal1_NonClterIdx ON T_Pet (animal)

 

图10非聚集索引

接着我们要查询表中animal = ‘Cat'的宠物信息具体的SQL代码如下

复制代码 代码如下:

SET STATISTICS PROFILE ON
SET STATISTICS TIME ON

SELECT animal, [name], sex, age
FROM T_Pet
WHERE animal = 'Cat'

SET STATISTICS PROFILE OFF
SET STATISTICS TIME OFF

如下图所示我们发现查询计划的最右边有两个步骤RID和索引查找。由于这两种查找方式相对于聚集索引查找要慢Clustered Index Seek。

 

图11查询计划

首先SQL Server查找索引值然后根据RID查找数据行直到找到符合查询条件的结果。

查询执行时间CPU 时间= 0 毫秒占用时间= 1 毫秒

图12查询结果

堆表非聚集索引

由于堆是不含聚集索引的表所以非聚集索引的叶节点将包含指向具体数据行的指针。

以前面的T_Pet表为例假设T_Pet使用animal列作为非聚集索引那么它的堆表非聚集索引结构如下图所示

图13堆表非聚集索引

通过上图我们发现非聚集索引通过双向链表连接而且叶节点包含指向具体数据行的指针。

如果我们要查找animal = ‘Dog'的信息首先我们遍历第一层索引然后数据库判断Dog属于Cat范围的索引接着遍历第二层索引然后找到Dog索引获取其中的保存的指针信息根据指针信息获取相应数据页中的数据接下来我们将通过具体的例子说明。

现在我们创建表employees然后给该表添加堆表非聚集索引具体SQL代码如下

复制代码 代码如下:

USE tempdb
---- Creates a sample table.
CREATE TABLE employees (
employee_id NUMERIC NOT NULL,
first_name VARCHAR(1000) NOT NULL,
last_name VARCHAR(900) NOT NULL,
date_of_birth DATETIME ,
phone_number VARCHAR(1000) NOT NULL,
junk CHAR(1000) ,
CONSTRAINT employees_pk PRIMARY KEY NONCLUSTERED (employee_id)
);

GO现在我们查找employee_id = 29976的员工信息。

复制代码 代码如下:

SELECT *
FROM employees
WHERE employee_id = 29976

查询计划如下图所示

图14查询计划

首先查找索引值employee_id = ‘29976'的索引然后根据RID查找符合条件的数据行所以说堆表索引的查询效率不如聚集表接下来我们将介绍聚集表的非聚集索引。

聚集表非聚集索引

当表上存在聚集索引时任何非聚集索引的叶节点不再是包含指针值而是包含聚集索引的索引值。

以前面的T_Pet表为例假设T_Pet使用animal列作为非聚集索引那么它的索引表非聚集索引结构如下图所示

图15索引表非聚集索引

通过上图我们发现非聚集索引通过双向链表连接而且叶节点包含索引表的索引值。

如果我们要查找animal = ‘Dog'的信息首先我们遍历第一层索引然后数据库判断Dog属于Cat范围的索引接着遍历第二层索引然后找到Dog索引获取其中的保存的索引值然后根据索引值获取相应数据页中的数据。

接下来我们修改之前的employees表首先我们删除之前的堆表非聚集索引然后增加索引表的非聚集索引具体SQL代码如下

复制代码 代码如下:

ALTER TABLE employees
DROP CONSTRAINT employees_pk

ALTER TABLE employees
ADD CONSTRAINT employees_pk PRIMARY KEY CLUSTERED (employee_id)
GO

SELECT * FROM employees
WHERE employee_id=29976

图16查询计划

索引的有效性
SQL Server每执行一个查询首先要检查该查询是否存在执行计划如果没有则要生成一个执行计划那么什么是执行计划呢简单来说它能帮助SQL Server制定一个最优的查询计划。关于查询计划请参考这里

下面我们将通过具体的例子说明SQL Server中索引的使用首先我们定义一个表testIndex它包含三个字段testIndexbitValue和filler具体的SQL代码如下

复制代码 代码如下:

-----------------------------------------------------------
---- Index Usefulness sample
-----------------------------------------------------------

CREATE TABLE testIndex
(
testIndex int identity(1,1) constraint PKtestIndex primary key,
bitValue bit,
filler char(2000) not null default (replicate('A',2000))
)

CREATE INDEX XtestIndex_bitValue on testIndex(bitValue)
GO

INSERT INTO testIndex(bitValue)
VALUES (0)
GO 20000 --runs current batch 20000 times.

INSERT INTO testIndex(bitValue)
VALUES (1)
GO 10 --puts 10 rows into table with value 1

接着我们查询表中bitValue = 0的数据行而且表中bitValue = 0的数据有2000行。

复制代码 代码如下:

SELECT *
FROM testIndex
WHERE bitValue = 0

图17查询计划

现在我们查询bitValue = 1的数据行。

SELECT *FROM testIndexWHERE bitValue = 1

图18查询计划

现在我们注意到对同一个表不同数据查询居然执行截然不同的查询计划这究竟是什么原因导致的呢

我们可以通过使用DBCC SHOW_STATISTICS查看到表中索引的详细使用情况具体SQL代码如下

复制代码 代码如下:

UPDATE STATISTICS dbo.testIndex
DBCC SHOW_STATISTICS('dbo.testIndex', 'XtestIndex_bitValue')
WITH HISTOGRAM


图19直方图

通过上面的直方图我们知道SQL Server估计bitValue = 0数据行行有约19989行而bitValue = 1估计约21SQL Server优化器根据数据量估算值采取不同的执行计划从而到达最优的查询性能由于bitValue = 0数据量大SQL Server只能提供扫描聚集索引获取相应数据行而bitValue = 1实际数据行只有10行SQL Server首先通过键查找bitValue = 1的数据行然后嵌套循环联接到聚集索引获得余下数据行。

总结 完整实例代码

复制代码 代码如下:

-- =============================================
-- Author: JKhuang
-- Create date: 04/20/2012
-- Description: Create sample for Clustered and
-- Nonclustered index.
-- =============================================

-----------------------------------------------------------
---- Create T_Pet table in tempdb with NONCLUSTERED INDEX.
-----------------------------------------------------------
USE tempdb
CREATE TABLE T_Pet
(
animal VARCHAR(20),
[name] VARCHAR(20),
sex CHAR(1),
age INT
)
CREATE UNIQUE NONCLUSTERED INDEX T_PetonAnimal1_NonClterIdx ON T_Pet (animal)
CREATE UNIQUE CLUSTERED INDEX T_PetonAnimal1_ClterIdx ON T_Pet (animal)
-----------------------------------------------------------
---- Insert data into data table.
-----------------------------------------------------------
DECLARE @i int
SET @i=0
WHILE(@i<1000000)
BEGIN
INSERT INTO T_Pet (
animal,
[name],
sex,
age
)
SELECT [dbo].random_string(11) animal,
[dbo].random_string(11) [name],
'F' sex,
cast(floor(rand()*5) as int) age
SET @i=@i+1
END
INSERT INTO T_Pet VALUES('Aardark', 'Hello', 'F', 1)
INSERT INTO T_Pet VALUES('Cat', 'Kitty', 'F', 2)
INSERT INTO T_Pet VALUES('Horse', 'Ma', 'F', 1)
INSERT INTO T_Pet VALUES('Turtles', 'SiSi', 'F', 4)
INSERT INTO T_Pet VALUES('Dog', 'Tomma', 'F', 2)
INSERT INTO T_Pet VALUES('Donkey', 'YoYo', 'F', 3)

SET STATISTICS PROFILE ON
SET STATISTICS TIME ON
SELECT animal, [name], sex, age
FROM T_Pet
WHERE animal = 'Cat'
SET STATISTICS PROFILE OFF
SET STATISTICS TIME OFF

-----------------------------------------------------------
---- Create employees table in tempdb.
-----------------------------------------------------------
CREATE TABLE employees (

employee_id NUMERIC NOT NULL,
first_name VARCHAR(1000) NOT NULL,
last_name VARCHAR(900) NOT NULL,
date_of_birth DATETIME ,
phone_number VARCHAR(1000) NOT NULL,
junk CHAR(1000) ,
--PK constraint defaults to clustered
CONSTRAINT employees_pk PRIMARY KEY (employee_id)
);
GO

-----------------------------------------------------------
---- Insert data into data table.
-----------------------------------------------------------
CREATE VIEW rand_helper AS SELECT RND=RAND();
GO
---- Generates random string function.
CREATE FUNCTION random_string (@maxlen int) RETURNS VARCHAR(255)
AS BEGIN
DECLARE @rv VARCHAR(255)
DECLARE @loop int
DECLARE @len int
SET @len = (SELECT CAST(rnd * (@maxlen-3) AS INT) +3
FROM rand_helper)
SET @rv = ''
SET @loop = 0
WHILE @loop < @len BEGIN
SET @rv = @rv
+ CHAR(CAST((SELECT rnd
FROM rand_helper) * 26 AS INT )+97)
IF @loop = 0 BEGIN
SET @rv = UPPER(@rv)
END
SET @loop = @loop +1;
END
RETURN @rv
END
GO
---- Generates random date function.
CREATE FUNCTION random_date (@mindaysago int, @maxdaysago int)
RETURNS VARCHAR(255)
AS BEGIN
DECLARE @rv datetime
SET @rv = (SELECT GetDate()
- rnd * (@maxdaysago-@mindaysago)
- @mindaysago
FROM rand_helper)
RETURN @rv
END
GO
---- Generates random int function.
CREATE FUNCTION random_int (@min int, @max int) RETURNS INT
AS BEGIN
DECLARE @rv INT
SET @rv = (SELECT rnd * (@max) + @min
FROM rand_helper)
RETURN @rv
END
GO
---- Inserts data into employees table.
WITH generator (n) as
(
select 1
union all
select n + 1 from generator
where N < 30000
)
INSERT INTO employees (employee_id
, first_name, last_name
, date_of_birth, phone_number, junk)
select n employee_id
, [dbo].random_string(11) first_name
, [dbo].random_string(11) last_name
, [dbo].random_date(20*365, 60*365) dob
, 'N/A' phone
, 'junk' junk
from generator
OPTION (MAXRECURSION 30000)
-----------------------------------------------------------
---- Index Usefulness sample
-----------------------------------------------------------
CREATE TABLE testIndex
(
testIndex int identity(1,1) constraint PKtestIndex primary key,
bitValue bit,
filler char(2000) not null default (replicate('A',2000))
)
CREATE INDEX XtestIndex_bitValue on testIndex(bitValue)
GO
INSERT INTO testIndex(bitValue)
VALUES (0)
GO 20000 --runs current batch 20000 times.
INSERT INTO testIndex(bitValue)
VALUES (1)
GO 10 --puts 10 rows into table with value 1
SELECT filler
FROM testIndex
WHERE bitValue = 1
UPDATE STATISTICS dbo.testIndex
DBCC SHOW_STATISTICS('dbo.testIndex', 'XtestIndex_bitValue')
WITH HISTOGRAM

时间: 2024-10-23 18:48:47

sqlserver 索引的一些总结_MsSql的相关文章

SqlServer 索引自动优化工具_MsSql

鉴于人手严重不足(当时算两个半人的资源),打消了逐个库手动去改的念头.当前的程序结构不允许搞革命的做法,只能搞搞改良,所以准备搞个自动化工具去处理.原型刚开发完,开会的时候以拿出来就遭到运维DBA团队强烈抵制,具体原因不详.最后无限延期.这里把思路分享下.欢迎拍砖. 整个思路是这样的,索引都是为查询和更新服务的,但是不合适的索引又会对插入和更新带来负面影响.面对表上现有的索引想识别那些是有效的不太可能.那么根据现有的数据使用情况重建所有的新索引不就解决了嘛.根据查询生成全新索引,然后和现有对比,

SqlServer索引的原理与应用

原文:SqlServer索引的原理与应用 索引的概念 索引的用途:我们对数据查询及处理速度已成为衡量应用系统成败的标准,而采用索引来加快数据处理速度通常是最普遍采用的优化方法. 索引是什么:数据库中的索引类似于一本书的目录,在一本书中使用目录可以快速找到你想要的信息,而不需要读完全书.在数据库中,数据库程序使用索引可以重啊到表中的数据,而不必扫描整个表.书中的目录是一个字词以及各字词所在的页码列表,数据库中的索引是表中的值以及各值存储位置的列表. 索引的利弊:查询执行的大部分开销是I/O,使用索

SQLSERVER的非聚集索引结构深度理解_MsSql

我们知道SQLSERVER的数据行的存储有两种数据结构:A: 堆   B :B树(binary 二叉树) 数据按照这种两种的其中一种来排序和存储,学过数据结构的朋友应该知道二叉树,为什麽用二叉树,因为方便用二分查找法来快速 找到数据.如果是堆,那么数据是不按照任何顺序排序的,也没有任何结构,数据页面也不是首尾相连的,不像B树,数据页面 使用双向链表首尾相连.堆表只依靠表里的IAM页(索引分配映射页)将堆的页面联系在一起,IAM里记录了页面编号,页面位置 除非表里有聚集索引,如果没有的话那么表里的

sqlserver索引的原理及索引建立的注意事项小结_MsSql

聚集索引,数据实际上是按顺序存储的,数据页就在索引页上.就好像参考手册将所有主题按顺序编排一样.一旦找到了所要搜索的数据,就完成了这次搜索,对于非聚集索引,索引是安全独立于数据本身结构的,在索引中找到了寻找的数据,然后通过指针定位到实际的数据. SQL Server中的索引使用标准的B-树来存储他们的信息,如下图所示,B-树通过查找索引中的一个关键之来提供对于数据的快速访问,B-树以相似的键记录聚合在一起,B不代表二叉(binary),而是代表balanced(平衡的),而B-树的一个核心作用就

优化 SQL Server 索引的小技巧_MsSql

在本文中,我将说明如何用SQL Server的工具来优化数据库索引的使用,本文还涉及到有关索引的一般性知识. 关于索引的常识 影响到数据库性能的最大因素就是索引.由于该问题的复杂性,我只可能简单的谈谈这个问题,不过关于这方面的问题,目前有好几本不错的书籍可供你参阅.我在这里只讨论两种SQL Server索引,即clustered索引和nonclustered索引.当考察建立什么类型的索引时,你应当考虑数据类型和保存这些数据的column.同样,你也必须考虑数据库可能用到的查询类型以及使用的最为频

真正高效的SQLSERVER分页查询(多种方案)_MsSql

Sqlserver数据库分页查询一直是Sqlserver的短板,闲来无事,想出几种方法,假设有表ARTICLE,字段ID.YEAR...(其他省略),数据53210条(客户真实数据,量不大),分页查询每页30条,查询第1500页(即第45001-45030条数据),字段ID聚集索引,YEAR无索引,Sqlserver版本:2008R2 第一种方案.最简单.普通的方法: 复制代码 代码如下: SELECT TOP 30 * FROM ARTICLE WHERE ID NOT IN(SELECT T

SQLSERVER SQL性能优化技巧_MsSql

1.选择最有效率的表名顺序(只在基于规则的优化器中有效) SQLSERVER的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表driving table)将被最先处理,在FROM子句中包含多个表的情况下,必须选择记录条数最少的表作为基础表,当SQLSERVER处理多个表时,会运用排序及合并的方式连接它们, 首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行排序:然后扫描第二个表(FROM子句中最后第二个表):最后将所有从第二个表中检索出的记录与第

SQL Server 数据库索引其索引的小技巧_MsSql

一.什么是索引 减少磁盘I/O和逻辑读次数的最佳方法之一就是使用[索引] 索引允许SQL Server在表中查找数据而不需要扫描整个表. 1.1.索引的好处: 当表没有聚集索引时,成为[堆或堆表] [堆]是一堆未加工的数据,以行标识符作为指向存储位置的指针.表数据没有顺序,也不能搜索,除非逐行遍历.这个过程称为[扫描].当存在聚集索引时,非聚集索引的指针由聚集索引所定义的值组成,所以聚集索引变得非常重要. 因为页面大小固定,所以列越少,所能存储的行就越多.由于非聚集索引通常不包含所有列,所以一般

SQL Server2014 哈希索引原理详解_MsSql

当一个key-value键值对传递给一个哈希函数的时候,经过哈希函数的计算之后,根据结果会把key-value键值对放在合适的hash buckets(哈希存储桶)里 举个栗子 我们假设对10取模( % 10 )就是哈希函数.如果key-value键值对的key是1525 ,传递到哈希函数,那么1525 会存放在第五个bucket里 因为5 as 1525 % 10 = 5. 同样,537 会存放在第七个bucket ,2982 会存放在第二个bucket ,依次类推 同样,在hash inde