SQL Server索引维护
索引维护的两个重要方面是索引碎片和统计信息。
一:索引碎片
降低碎片的产生,当索引上的页不在具有物理连续性时,就会产生碎片,下面的情景会产生碎片:
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索引维护的更多相关文章
- SQL Server 索引维护(1)——系统常见的索引问题
前言: 在很多系统中,比如本人目前管理的数据库,索引经常被滥用,甚至使用DTA(数据库引擎优化顾问)来成批创建索引(DTA目前个人认为它的真正用处应该是在发现缺失的统计信息,在以前的项目中,用过一次D ...
- SQL Server 索引维护:系统常见的索引问题
在很多系统中,比如本人目前管理的数据库,索引经常被滥用,甚至使用DTA(数据库引擎优化顾问)来成批创建索引(DTA目前个人认为它的真正用处应该是在发现缺失的统计信息,在以前的项目中,用过一次DTA,里 ...
- SQL Server 索引维护(1)——如何获取索引使用情况
前言: 在前面一文中,已经提到了三类常见的索引问题,那么问题来了,当系统出现这些问题时,该如何应对? 简单而言,需要分析现有系统的行为,然后针对性地对索引进行处理: 对于索引不足的情况:检查缺少索引的 ...
- SQL Server 索引维护sql语句
使用以下脚本查看数据库索引碎片的大小情况: 复制代码代码如下: DBCC SHOWCONTIG WITH FAST, TABLERESULTS, ALL_INDEXES, NO_INFOMSGS 以 ...
- SQL SERVER 索引维护
-- 全数据库索引重建 DECLARE @name varchar(100)DECLARE authors_cursor CURSOR FOR Select [name] from sysobject ...
- 转: SQL Server索引的维护 - 索引碎片、填充因子
转:http://www.cnblogs.com/kissdodog/archive/2013/06/14/3135412.html 实际上,索引的维护主要包括以下两个方面: 页拆分 碎片 这两个问题 ...
- SQL Server索引的维护 - 索引碎片、填充因子 <第三篇>
实际上,索引的维护主要包括以下两个方面: 页拆分 碎片 这两个问题都和页密度有关,虽然两者的表现形式在本质上有所区别,但是故障排除工具是一样的,因为处理是相同的. 对于非常小的表(比64KB小得多), ...
- SQL Server索引 (原理、存储)聚集索引、非聚集索引、堆 <第一篇>
一.存储结构 在SQL Server中,有许多不同的可用排列规则选项. 二进制:按字符的数字表示形式排序(ASCII码中,用数字32表示空格,用68表示字母"D").因为所有内容都 ...
- SQL Server索引设计 <第五篇>
SQL Server索引的设计主要考虑因素如下: 检查WHERE条件和连接条件列: 使用窄索引: 检查列的选择性: 检查列的数据类型: 考虑列顺序: 考虑索引类型(聚集索引OR非聚集索引): 一.检查 ...
随机推荐
- 论文笔记:Selective Search for Object Recognition
与 Selective Search 初次见面是在著名的物体检测论文 「Rich feature hierarchies for accurate object detection and seman ...
- Boost.Asio的使用技巧
基本概念 Asio proactor I/O服务 work类 run() vs poll() stop() post() vs dispatch() buffer类 缓冲区管理 I/O对象 socke ...
- 效率较高的php下读取文本文件的代码
主要用下面这两个方法fread和 fgets的区别大家需要注意下 fread :以字节位计算长度,按照指定的长度和次数读取数据,遇到结尾或完成指定长度读取后停止. fgets :整行读取,遇 ...
- chan array初始化
package main import "fmt" func run() { chann[0] <- 1 } var chann = make([]chan int, 2) ...
- vue-cli(vue脚手架)超详细教程
都说Vue2简单上手容易,的确,看了官方文档确实觉得上手很快,除了ES6语法和webpack的配置让你感到陌生,重要的是思路的变换,以前用jq随便拿全局变量和修改dom的锤子不能用了,vu ...
- python第13天
装饰器 装饰器本质上就是一个python函数,他可以让其他函数在不需要做任何改动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象. 装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等 ...
- [转]ASCII码表及扩展ASCII码表,方便查阅
ASCII码表可以看成由三部分组成: 第一部分:由00H到1FH共32个,一般用来通讯或作为控制之用.有些可以显示在屏幕上,有些则不能显示,但能看到其效果(如换行.退格).如下表: 第二部分:是由20 ...
- 用sitemap做主页的菜单栏
首先打开vs--> 新建项-->选择站点地图. 站点地图建好了 其中具体的节点根据自己情况配好就行. 接下来是两个非常重要的类: using System.Collections.Gen ...
- ant自动编译打包android项目
源代码及可执行文件下载地址:http://files.cnblogs.com/rainboy2010/antdemo.zip Android打包APK的流程如下: 下面我们开始尝试使用ant进行ap ...
- Swift中使用oc代码桥接设置
1 将oc的代码拖入项目中 2 新建一个头文件 在头文件中导入你想用的oc头文件 import "****.h" 3 在设置build Setting 中搜索bird 找到 Ob ...