索引维护的两个重要方面是索引碎片和统计信息。

一:索引碎片

降低碎片的产生,当索引上的页不在具有物理连续性时,就会产生碎片,下面的情景会产生碎片:

INSERT操作、UPDATE操作、DBCC SHRINKDATABASE操作

除了查询数据之外,对索引的绝大部分操作都会引起碎片,当然如果数据库是只读的则另当别论。创建索引后,需要实时或者周期性监控索引的碎片,以便降低碎片带来的性能影响。

1.产生碎片的操作

碎片问题主要通过sys.dm_db_index_physical_stats来查看,当索引上的页不在具有连续性时就会产生碎片,碎片就是索引上页拆分的物理结果。

(1)插入操作 INSERT操作子聚集索引和非聚集索引上都可以产生碎片。

在设计聚集索引时,有时会使用业务键或者GUID等类型做聚集索引,这时候就很容易产生碎片。

使用NEWGUID产生的唯一键具有唯一性,但又很随机。当一个新数据插入聚集索引时,很高几率会插在一个已经存在数据的页上,当空间不够时,就会产生分页,从而导致碎片。

 IF OBJECT_ID('dbo.Table_GUID') IS NOT NULL
DROP TABLE dbo.Table_GUID
CREATE TABLE Table_GUID
(
RowID UNIQUEIDENTIFIER CONSTRAINT DF_GUIDValue DEFAULT NEWID()--使用GUID作为默认值
,Name sysname,Value VARCHAR(2000) ); --插入数据,注意此时还没有创建索引
INSERT INTO dbo.Table_GUID
( Name, Value )
SELECT name,REPLICATE('X',2000)
FROM sys.columns --在列上创建聚集索引
CREATE CLUSTERED INDEX CLUS_UsingUniqueidentifier ON dbo.Table_GUID(RowID);
--查看平均碎片
SELECT
index_type_desc,
index_depth,
page_count,
record_count,
CAST(avg_fragmentation_in_percent AS DECIMAL(6,2)) AS avg_fragmentation_in_percent,
fragment_count,
avg_fragment_size_in_pages,
CAST(avg_page_space_used_in_percent AS DECIMAL(6,2)) AS avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(),OBJECT_ID(N'dbo.Table_GUID'),NULL,NULL,'DETAILED')

平均碎皮为0,因为在插入后才建索引:

  --执行插入操作
--插入新数据
INSERT INTO dbo.Table_GUID
( Name, Value )
SELECT name,REPLICATE('X',2000) FROM sys.objects
--查看平均碎片
SELECT
index_type_desc,
index_depth,
page_count,
record_count,
CAST(avg_fragmentation_in_percent AS DECIMAL(6,2)) AS avg_fragmentation_in_percent,
fragment_count,
avg_fragment_size_in_pages,
CAST(avg_page_space_used_in_percent AS DECIMAL(6,2)) AS avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(),OBJECT_ID(N'dbo.Table_GUID'),NULL,NULL,'DETAILED')

碎片迅速增长,这种情况不是简单的重建、重组索引可以解决的,更主要的是改变索引的设计,业务键和GUID存在类似的情况

另外一个在INSET操作过程中产生碎片的地方就是在非聚集索引上,非聚集索引上没有强烈要求自增,当对一个产品名加非聚集索引时,下一个新的数据可能以M字母开头,这样一来,就必须存放在接近索引的中间部分。如果没有空间,同样也会产生分页从而导致碎片。

 --在前面的例子中加一个非聚集索引
CREATE NONCLUSTERED INDEX IX_Name ON dbo.Table_GUID(Name) INCLUDE (Value); --查看平均碎片 再次执行相同的插入,然后再次检查
INSERT INTO dbo.Table_GUID
( Name, Value )
SELECT name,REPLICATE('X',2000) FROM sys.objects --查看平均碎片
SELECT
index_type_desc,
index_depth,
page_count,
record_count,
CAST(avg_fragmentation_in_percent AS DECIMAL(6,2)) AS avg_fragmentation_in_percent,
fragment_count,
avg_fragment_size_in_pages,
CAST(avg_page_space_used_in_percent AS DECIMAL(6,2)) AS avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(),OBJECT_ID(N'dbo.Table_GUID'),NULL,NULL,'DETAILED')

碎片迅速增加,当INSET操作发生时,产生碎片在所难免,唯一要做的是,尽可能降低碎片的产生速率

(2)跟新操作

IF OBJECT_ID('dbo.Update_Fr') IS NOT NULL
DROP TABLE dbo.Update_Fr;
CREATE TABLE dbo.Update_Fr
(
RowID INT IDENTITY(1,1),
Name sysname,
Value VARCHAR(2000)
); INSERT INTO dbo.Update_Fr
(
name,Value
)SELECT name,REPLICATE('X',1000)
FROM sys.columns
CREATE CLUSTERED INDEX CLUS_UsingUniqueidentifier ON dbo.Update_Fr(RowID); --检查一下索引情况
SELECT
index_type_desc,
index_depth,
page_count,
record_count,
CAST(avg_fragmentation_in_percent AS DECIMAL(6,2)) AS avg_fragmentation_in_percent,
fragment_count,
avg_fragment_size_in_pages,
CAST(avg_page_space_used_in_percent AS DECIMAL(6,2)) AS avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(),OBJECT_ID(N'dbo.Table_GUID'),NULL,NULL,'DETAILED')

  --更新数据,让数据变长
UPDATE dbo.Update_Fr
SET Value= REPLICATE('X',2000)
WHERE RowID%5=1

同样碎片增长非常快。

第二种情况,即键值上的改变致使碎片产生。当索引上键值改变时,数据必须更改存放位置,如果在聚集索引上的键值经常需要改变,意味着聚集索引设计的不合理

创建一个非聚集索引

 --创建一个非聚集索引
CREATE NONCLUSTERED INDEX IX_Name ON dbo.Update_Fr(Name) INCLUDE (Value);

--通过REVERSE函数把名称反转,监控更新前后的碎片操作

 SELECT
index_type_desc,
index_depth,
index_level,
page_count,
record_count,
CAST(avg_fragmentation_in_percent AS DECIMAL(6,2) AS avg_fragmentation_in_percent,
fragment_count,
avg_fragment_size_in_pages,
CAST(avg_page_space_used_in_percent AS DECIMAL(6,2)) AS avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(),OBJECT_ID('dbo.Update_Fr'),NULL,NULL,'DETAILED') UPDATE dbo.Update_Fr
SET name =REVERSE(Name) WHERE RowID%9=1 SELECT
index_type_desc,
index_depth,
index_level,
page_count,
record_count,
CAST(avg_fragmentation_in_percent AS DECIMAL(6,2) AS avg_fragmentation_in_percent,
fragment_count,
avg_fragment_size_in_pages,
CAST(avg_page_space_used_in_percent AS DECIMAL(6,2)) AS avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(),OBJECT_ID('dbo.Update_Fr'),NULL,NULL,'DETAILED')

3.收缩操作:

收缩可以控制数据库或者文件的大小,执行的时候,从数据文件中最大的页号所在的区开始向前回收,但是这个操作不会考虑已经被移除的数据页,只会从文件的最后一页开始向前回收。

 --收缩操作
GO
IF DB_ID(N'Fragmentation') IS NOT NULL
DROP DATABASE Fragmentation
GO
CREATE DATABASE Fragmentation
GO
USE Fragmentation
GO
IF OBJECT_ID('dbo.FirstTable') IS NOT NULL
DROP TABLE dbo.FirstTable CREATE TABLE dbo.FirstTable
(
RowID INT IDENTITY(1,1),
Name sysname,
value VARCHAR(2000),
CONSTRAINT PK_FirstTable PRIMARY KEY CLUSTERED(RowID)
); INSERT INTO dbo.FirstTable
( Name, value )
SELECT name,REPLICATE('X',2000) FROM sys.columns IF OBJECT_ID('dbo.SecondTable') IS NOT NULL
DROP TABLE dbo.SecondTable CREATE TABLE dbo.SecondTable
(
RowID INT IDENTITY(1,1),
Name sysname,
value VARCHAR(2000),
CONSTRAINT PK_SecondTable PRIMARY KEY CLUSTERED(RowID)
); INSERT INTO dbo.SecondTable
( Name, value )
SELECT name,REPLICATE('X',2000) FROM sys.columns
GO
INSERT INTO dbo.FirstTable
( Name, value )
SELECT name,REPLICATE('X',2000) FROM sys.columns INSERT INTO dbo.SecondTable
( Name, value )
SELECT name,REPLICATE('X',2000) FROM sys.columns --检查索引碎片,在删除表SecondTable
SELECT
index_type_desc,
index_depth,
index_level,
page_count,
record_count,
CAST(avg_fragmentation_in_percent AS DECIMAL(6,2)) AS avg_fragmentation_in_percent,
fragment_count,
avg_fragment_size_in_pages,
CAST(avg_page_space_used_in_percent AS DECIMAL(6,2)) AS avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(),OBJECT_ID('dbo.FirstTable'),NULL,NULL,'DETAILED') GO
IF OBJECT_ID('dbo.SecondTable') IS NOT NULL
DROP TABLE dbo.SecondTable; GO
SELECT
index_type_desc,
index_depth,
index_level,
page_count,
record_count,
CAST(avg_fragmentation_in_percent AS DECIMAL(6,2)) AS avg_fragmentation_in_percent,
fragment_count,
avg_fragment_size_in_pages,
CAST(avg_page_space_used_in_percent AS DECIMAL(6,2)) AS avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(),OBJECT_ID('dbo.FirstTable'),NULL,NULL,'DETAILED')

由于SQL Server不会自动回收,所以调用DBCC SHRINKDATABASE命令来收缩数据库。

 DBCC SHRINKDATABASE(Fragmentation)

查看索引碎片:

SELECT
index_type_desc,
index_depth,
index_level,
page_count,
record_count,
CAST(avg_fragmentation_in_percent AS DECIMAL(6,2)) AS avg_fragmentation_in_percent,
fragment_count,
avg_fragment_size_in_pages,
CAST(avg_page_space_used_in_percent AS DECIMAL(6,2)) AS avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(),OBJECT_ID('dbo.FirstTable'),NULL,NULL,'DETAILED')

碎片明显增加

2.碎片带来的问题

1.带来额外的I/O

2.影响连续性读

数据页越多,延时越久,性能越差

 IF OBJECT_ID('dbo.IndexIO') IS NOT NULL
DROP TABLE dbo.IndexIO;
CREATE TABLE dbo.IndexIO(
RowID INT IDENTITY(1,1),
Name sysname,
Value NVARCHAR(2000)
);
INSERT INTO dbo.IndexIO
( RowID, Name, Value )
SELECT name,REPLICATE('X',1000) FROM sys.columns
CREATE CLUSTERED INDEX CLUS_IndexIO ON dbo.IndexIO(RowID); UPDATE dbo.IndexIO
SET Value=REPLICATE('X',2000) WHERE RowID%5=1
--查看索引占用的页数
SELECT i.name,ps.in_row_data_page_count
FROM sys.indexes i
INNER JOIN sys.dm_db_partition_stats ps
ON i.object_id=ps.object_id AND i.index_id=ps.index_id
WHERE i.name='CLUS_IndexIO' --重建索引
ALTER INDEX CLUS_IndexIO ON dbo.IndexIO REBUILD
--再次查看
SELECT i.name,ps.in_row_data_page_count
FROM sys.indexes i
INNER JOIN sys.dm_db_partition_stats ps
ON i.object_id=ps.object_id AND i.index_id=ps.index_id
WHERE i.name='CLUS_IndexIO'

在表上创建索引,并进行了一次UPDATA操作后,产生了碎片,索引占用页变成了921;而在重建索引之后,占用的页减少到了724,随着操作的增多,索引所占的页也会增多,操作时所用的I/O也增多。

(2)连续读

碎片的另外一个影响就是降低连续读,把连续的数据页一次性加载到内存中,供后续使用,这样能很大程度上降低每次读取的I/O数量

3.降低碎片的操作

索引重建、索引重组、和删除重建

(1)索引重建

创建一个与现有索引定义一样,同时保存原有索引可用的方法,在创建完毕后,就删除索引。

好处:重建的索引是按照原有索引定义的,而且它是一个具有连续页的索引,在高度碎片化的索引中,重建是最快的方式,

提示:当聚集索引包含了image、ntext、text、varchar(max)、nvarchar(max)、varbinary(max)、xml等这些类型时,不能使用这种方式。

CREATE INDEX 和ALTER INDEX重建时,需要考虑下面的因素:

索引的定义需要修改,比如增、删列等,用CREATE INDEX

索引需要移动到别的文件组,用CREATE  INDEX

索引分区需要改变,也用CREATE INDEX

多于一个索引需要在同一个语句中创建时,或者索引中的一个分区需要重建,用ALTER INDEX语句

重建索引的负面影响之一是重建过程中对空间的占用会很高,平均需要占用120%的额外空间,

(2)重组索引

通过重组索引,索引上的逻辑顺序和物理顺序就相同了,重组索引相对开销比较低,比较适合常规使用,重组时使用ALTER INDEX并带上REORGANIZE选项,还能对单一分区的索引进行重组,这是REBUILD 选项中不支持的

(3)删除并重建索引
索引除了性能之外还有组织数据的功能,如果对大表频繁操作的表、资源压力很大的系统进行这种删除操作,除了增加压力之外,还容易导致数据混乱。
建议使用如下脚本重建索引:
CREATE NONCLUSTERED COLUMNSTORE INDEX csindx_simple ON  simpletable(orderDateKey,DueDateKey,ShipDateKey) WITH(DROP_EXISTING)

如果索引是聚集索引,那么表上其他索引都会在删除聚集索引后被迫全部重建,因为聚集索引和堆表以不同结构存放数据。没有聚集索引的表就是堆表,所以删除聚集索引之后的表就成了堆表。

如果索引上是主键或者具有唯一性约束,或者有外键,那么即使删除也会增加数据混乱的分险

让SqlServer自己维护统计信息

1.使用DMO:

  SELECT DueDate FROM sales.SalesOrderHeader
WHERE duedate ='2001-07-13 00:00:00.000'
AND OrderDate='2001-07-13 00:00:00.000'
GO
SELECT DueDate FROM sales.SalesOrderHeader
WHERE OrderDate BETWEEN '20010701' AND '20010731'
AND duedate BETWEEN '20010701' AND '20010731'
GO
SELECT DueDate,OrderDate FROM sales.SalesOrderHeader
WHERE duedate BETWEEN '20010701' AND '20010731'
GO
SELECT CustomerID,OrderDate FROM sales.SalesOrderHeader
WHERE DueDate BETWEEN '20010701' AND '20010731'
AND OrderDate BETWEEN '20010701' AND '20010731'

--使用DMO展示信息的产生

SELECT DB_NAME(mid.database_id)  AS database_name,
OBJECT_NAME(mid.object_id,mid.database_id) AS table_name,
mid.equality_columns,
mid.inequality_columns,
mid.included_columns,
(migs.user_seeks + migs.user_scans)* migs.avg_user_impact AS Impact,
migs.avg_total_user_cost * (migs.avg_user_impact/100.0)*(migs.user_seeks+migs.user_scans) AS Score,
migs.user_seeks,
migs.user_scans
FROM sys.dm_db_missing_index_details mid
INNER JOIN sys.dm_db_missing_index_groups mig ON mid.index_handle=mig.index_handle
INNER JOIN sys .dm_db_missing_index_group_stats migs ON mig.index_group_handle=migs.group_handle
ORDER BY migs.avg_total_user_cost * (migs.avg_user_impact/100.0)*
(migs.user_seeks+migs.user_scans) DESC

重点关注Impact和Score列,Impact列是优化器预估加了索引之后,用户的查找和扫描操作“可能”提高的程度;Score是一个预估能减少的开销百分比。

最后的缺失索引建议应该如下使用:

CREATE NONCLUSTERED INDEX missing_index_SalesOrderHeader
ON Sales.SalesOrderHeader([DueDate],[OrderDate])
INCLUDE ([CustomerID])

2.数据库引擎优化顾问

DTA有一个缺点:就是强烈依赖于当前数据库的负载,少量的改动都会导致DTA给出的建议有很大误差。

(1.)针对单语句优化(缺失索引)

SELECT DueDate FROM sales.SalesOrderHeader
WHERE duedate ='2001-07-13 00:00:00.000'
AND OrderDate='2001-07-13 00:00:00.000'

在查询界面右键,然后选择在DTA中分析查询选项即可。

--使用DMO侦测索引问题
--查找未被使用过的索引,可以考虑删除
SELECT '['+DB_NAME()+'].['+su.[name]+'].['+o.[name]+']' AS [statement],i.[name] AS [index_name],
ddius.[user_seeks]+ddius.[user_scans] +ddius.[user_lookups] AS [user_reads],
ddius.[user_updates] AS [user_writes],
SUM(sp.rows) AS [total_rows]
FROM sys.dm_db_index_usage_stats ddius
INNER JOIN sys.indexes i ON ddius.[object_id]=i.[object_id] AND i.[index_id]=ddius.[index_id] INNER JOIN sys.partitions SP ON ddius.[object_id]=SP.[object_id] AND sp.[index_id]=ddius.[index_id] INNER JOIN sys.objects o ON ddius.[object_id] =o.[object_id]
INNER JOIN sys.sysusers su ON o.[schema_id]=su.[uid]
WHERE ddius.[database_id] =DB_ID() --current database only
AND OBJECTPROPERTY(ddius.[object_id],'IsUserTable')=1
AND ddius.[index_id]>0
GROUP BY su.[name],o.[name],i.[name],ddius.[user_seeks]+ddius.[user_scans]+ddius.[user_lookups],ddius.[user_updates]
HAVING ddius.[user_seeks]+ddius.[user_scans]+ddius.[user_lookups]=0
ORDER BY ddius.[user_updates] DESC, su.[name],o.[name],i.[name] --可能不合理的非聚集索引(读大于写)Insert和Update操作对索引碎片的影响非常大
SELECT
OBJECT_NAME(ddius.[object_id]) AS [Table Name],
i.name AS [Index Name],
i.index_id,
ddius.user_updates AS [Total_Writes],
ddius.user_seeks,
ddius.user_scans,
ddius.user_lookups AS [Total Reads],
ddius.user_updates-(user_seeks+ddius.user_scans+ddius.user_lookups) AS [Difference]
FROM sys.dm_db_index_usage_stats AS ddius WITH(NOLOCK)
INNER JOIN sys.indexes AS i WITH(NOLOCK) ON ddius.[object_id]=i.[object_id] AND i.index_id =ddius.index_id
WHERE OBJECTPROPERTY(ddius.[object_id],'IsUserTable')=1
AND ddius.database_id=DB_ID()
AND ddius.user_updates>(user_seeks+user_scans+user_lookups)
AND i.index_id>1
ORDER BY [Difference] DESC,[Total_Writes] DESC,[Total Reads] ASC; --索引上的碎片,只针对页数超过500页
SELECT
'['+DB_NAME()+'].['+OBJECT_SCHEMA_NAME(ddips.[object_id],DB_ID())
+'].['+OBJECT_NAME(ddips.[object_id],DB_ID())+']' AS [statement],
i.[name] AS [index_name],ddips.[index_type_desc], ddips.[partition_number],
ddips.[alloc_unit_type_desc],ddips.[index_depth],ddips.[index_level],
CAST(ddips.[avg_fragmentation_in_percent] AS SMALLINT) AS [avg_frag_%],
CAST(ddips.[avg_fragment_size_in_pages] AS SMALLINT ) AS [avg_frag_size_in_pages],
ddips.[fragment_count],
ddips.[page_count]
FROM sys.dm_db_index_physical_stats(DB_ID(),NULL,NULL,NULL,'limited') AS ddips
INNER JOIN sys.[indexes] i ON ddips.[object_id]=i.[object_id] AND ddips.[index_id]=i.[index_id]
WHERE ddips.[avg_fragmentation_in_percent]>15
AND ddips.[page_count]>500
ORDER BY ddips.[avg_fragmentation_in_percent],
OBJECT_NAME(ddips.[object_id],DB_ID()),i.[name] --还能监控锁情况
SELECT '['+DB_NAME(ddios.[database_id])+'].['+su.[name]+'].['+o.[name]+']' AS [statement],
i.[name] AS 'index_name',
ddios.[partition_number],
ddios.[row_lock_count],
ddios.[row_lock_wait_count],
CAST(100.0*ddios.[row_lock_wait_count]/(ddios.[row_lock_count]) AS DECIMAL(5,2)) AS [%_time_blocked],
ddios.[row_lock_wait_in_ms],
CAST(1.0*ddios.[row_lock_wait_in_ms]/ddios.[row_lock_wait_count] AS DECIMAL(15,2)) AS [avg_row_lock_wait_in_ms]
FROM sys.dm_db_index_operational_stats(DB_ID(),NULL,NULL,NULL) ddios
INNER JOIN sys.indexes i ON ddios.[object_id]=i.[object_id]
AND i.[index_id]=ddios.[index_id]
INNER JOIN sys.objects o ON ddios.[object_id]=o.[object_id]
INNER JOIN sys.sysusers su ON o.[schema_id]=su.[uid]
WHERE ddios.row_lock_wait_count>0
AND OBJECTPROPERTY(ddios.[object_id],'IsUserTable')=1
AND i.[index_id]>0
ORDER BY ddios.[row_lock_wait_count] DESC,su.[name],
o.[name],i.[name] --识别闩锁
SELECT '['+ DB_NAME()+ '].['+ OBJECT_SCHEMA_NAME(ddios.[object_id])+'].['+ OBJECT_NAME(ddios.[object_id])+']' AS [objcet_name],
i.[name] AS index_name,
ddios.page_io_latch_wait_count,
ddios.page_io_latch_wait_in_ms,
(ddios.page_io_latch_wait_in_ms/ddios.page_io_latch_wait_count) AS avg_page_io_latch_wait_in_ms
FROM sys.dm_db_index_operational_stats(DB_ID(),NULL,NULL,NULL) ddios
INNER JOIN sys.indexes i ON ddios.[object_id]=i.[object_id] AND i.index_id=ddios.index_id
WHERE ddios.page_io_latch_wait_count>0
AND OBJECTPROPERTY(i.object_id,'IsUserTable')=1
ORDER BY ddios.page_io_latch_wait_count DESC,
avg_page_io_latch_wait_in_ms DESC

SQL Server索引维护的更多相关文章

  1. SQL Server 索引维护(1)——系统常见的索引问题

    前言: 在很多系统中,比如本人目前管理的数据库,索引经常被滥用,甚至使用DTA(数据库引擎优化顾问)来成批创建索引(DTA目前个人认为它的真正用处应该是在发现缺失的统计信息,在以前的项目中,用过一次D ...

  2. SQL Server 索引维护:系统常见的索引问题

    在很多系统中,比如本人目前管理的数据库,索引经常被滥用,甚至使用DTA(数据库引擎优化顾问)来成批创建索引(DTA目前个人认为它的真正用处应该是在发现缺失的统计信息,在以前的项目中,用过一次DTA,里 ...

  3. SQL Server 索引维护(1)——如何获取索引使用情况

    前言: 在前面一文中,已经提到了三类常见的索引问题,那么问题来了,当系统出现这些问题时,该如何应对? 简单而言,需要分析现有系统的行为,然后针对性地对索引进行处理: 对于索引不足的情况:检查缺少索引的 ...

  4. SQL Server 索引维护sql语句

    使用以下脚本查看数据库索引碎片的大小情况: 复制代码代码如下: DBCC SHOWCONTIG WITH FAST, TABLERESULTS, ALL_INDEXES, NO_INFOMSGS  以 ...

  5. SQL SERVER 索引维护

    -- 全数据库索引重建 DECLARE @name varchar(100)DECLARE authors_cursor CURSOR FOR Select [name] from sysobject ...

  6. 转: SQL Server索引的维护 - 索引碎片、填充因子

    转:http://www.cnblogs.com/kissdodog/archive/2013/06/14/3135412.html 实际上,索引的维护主要包括以下两个方面: 页拆分 碎片 这两个问题 ...

  7. SQL Server索引的维护 - 索引碎片、填充因子 <第三篇>

    实际上,索引的维护主要包括以下两个方面: 页拆分 碎片 这两个问题都和页密度有关,虽然两者的表现形式在本质上有所区别,但是故障排除工具是一样的,因为处理是相同的. 对于非常小的表(比64KB小得多), ...

  8. SQL Server索引 (原理、存储)聚集索引、非聚集索引、堆 <第一篇>

    一.存储结构 在SQL Server中,有许多不同的可用排列规则选项. 二进制:按字符的数字表示形式排序(ASCII码中,用数字32表示空格,用68表示字母"D").因为所有内容都 ...

  9. SQL Server索引设计 <第五篇>

    SQL Server索引的设计主要考虑因素如下: 检查WHERE条件和连接条件列: 使用窄索引: 检查列的选择性: 检查列的数据类型: 考虑列顺序: 考虑索引类型(聚集索引OR非聚集索引): 一.检查 ...

随机推荐

  1. centos U盘挂载问题

    查看u盘路径 fdisk -l Disk /dev/sda: 16.2 GB, 16236150784 bytes, 31711232 sectors Units = sectors of 1 * 5 ...

  2. 【转】实习小记-python中可哈希对象是个啥?what is hashable object in python?

    [转]实习小记-python中可哈希对象是个啥?what is hashable object in python? 废话不多说直接祭上python3.3x的文档:(原文链接) object.__ha ...

  3. Git学习笔记07-删除文件

    在Git中,删除也是一种修改.先新建一个文件,添加并提交.然后删除下看看. 一般删除直接从工作区把文件删了,或者使用rm命令 ​ 这是使用git status查看状态,会告诉我们删了哪个文件 ​ 这个 ...

  4. CentOS(Linux)中解决MySQL乱码

    环境:CentOS 6.3.mysql5.1 Centos 6.3在上安装mysql client和server之后,出现乱码,不得不修改编码. 注意: 关于utf8和gbk的区别详细见:linux中 ...

  5. Linux下设置时间

    Linux下设置时间 提供两种最根本有效的方式,就是更改时区.这里以更改为国内上海时间例子,其他地方时区同理. 方法一 备份文件 mv /etc/localtime /etc/localtime.ba ...

  6. js导出excel增加表头、mso-number-format定义数据格式

    问题1:增加表头 js导出表格时,只会导出table里的展现出的内容,如需增加表头等内容需要在页面获取的字符串中拼接表头的相关字符串,详细介绍如下: tableString:新增的表头内容字符串: c ...

  7. C语言 16进制转float

    float hex_to_float(uint8_t *data) { float num = 0.0; uint8_t dd[4] = {data[0], data[1], data[2], dat ...

  8. iOS post提交数据有嵌套数组的处理方法

    2017年11月21日17:11:43 解决办法, 修改iOS框架里的代码: http://www.jianshu.com/p/130daa0c2fe7 确实有效, 要不然,  内层的每一个键值对都会 ...

  9. 【原创】大数据基础之Flume(2)kudu sink

    kudu中的flume sink代码路径: https://github.com/apache/kudu/tree/master/java/kudu-flume-sink kudu-flume-sin ...

  10. 《Spring5官方文档》新功能(4,3)

    <Spring5官方文档>新功能 原文链接 译者:supriseli Spring框架的新功能 这一章主要提供Spring框架新的功能和变更. 升级到新版本的框架可以参考.Spring g ...