--总结:SQLServer 中没有函数索引和Hash索引,而某些业务需求或者说是为了性能考虑
1,在计算列上建索引,实现“函数索引”的功能
SQLServer在建表的时候允许使用计算列,可以借助这个计算列来实现函数索引的功能,这里举例说明一下
Create Table TestFunctionIndex
(
id int identity(1,1),
val varchar(50),
subval as LOWER(SUBSTRING(val,10,4)) persisted --增加一个持久化计算列
) GO
--在持久化计算列上建立索引
create index idx_var on TestFunctionIndex(val) GO
create index idx_subvar on TestFunctionIndex(subval) GO
--插入10W行测试数据
insert into TestFunctionIndex(val) values (NEWID()) go 100000
在有索引的字段上使用函数之后,是无法使用索引的
select *from TestFunctionIndex where lower(substring(val,10,4)) ='a'
如果直接在计算列上查询,就可以正常地使用到索引了
select *from TestFunctionIndex where subval ='a'
--筛选索引是一种经过优化的非聚集索引,尤其适用于涵盖从定义完善的数据子集中选择数据的查询。筛选索引使用筛选谓词对表中的部分行进行索引
在列中只有少量相关值需要查询时,可以针对值的子集创建筛选索引。例如,当列中的值大部分为 NULL 并且查询只从非 NULL 值中进行选择时,可以为非 NULL 数据行创建筛选索引
USE AdventureWorks;
GO
IF EXISTS (SELECT name FROM sys.indexes
WHERE name = N'FIBillOfMaterialsWithEndDate'
AND object_id = OBJECT_ID (N'Production.BillOfMaterials'))
DROP INDEX FIBillOfMaterialsWithEndDate
ON Production.BillOfMaterials
GO
CREATE NONCLUSTERED INDEX FIBillOfMaterialsWithEndDate
ON Production.BillOfMaterials (ComponentID, StartDate)
WHERE EndDate IS NOT NULL;
GO
筛选索引 FIBillOfMaterialsWithEndDate 对下面的查询有效。您可以显示查询执行计划,
以确定查询优化器是否使用了此筛选索引。有关如何显示查询执行计划的信息,请参阅分析查询。
SELECT ProductAssemblyID, ComponentID, StartDate
FROM Production.BillOfMaterials
WHERE EndDate IS NOT NULL;
查看 SQL Server 的指定数据库索引碎片百分比 (SQL)
---外部碎片导致磁盘上的索引页面不连续,新的叶子页面和原始叶子页面离的很远,物理顺序和逻辑顺序不同.
select b.name,c.name as indexname, a.index_type_desc,a.index_depth,a.avg_fragmentation_in_percent,
a.avg_page_space_used_in_percent,a.fragment_count ,a.avg_fragment_size_in_pages,a.page_count
from sys.dm_db_index_physical_stats(DB_ID(N'MYTEST'),NULL,NULL,NULL,'DETAILED') as a
inner join sys.objects as b
on a.object_id =b.object_id
inner join sys.indexes as c on a.object_id=c.object_id and a.index_id=c.index_id
order by a.avg_fragmentation_in_percent desc,a.object_id asc
--如果 avg_fragmentation_in_percent 的%比大于30(可以自定义%比值) 则
ALTER INDEX INDEX_NAME ON TABLE_NAME REBUILD WITH(ONLINE=ON) ---联机不锁定表来重新创建索引,以减小索引碎片
--如果小于30 则
ALTER INDEX INDEX_NAME ON TABLE_NAME REORGANIZE --脱机重新创建索引,以减小索引碎片
--避免重新创建聚簇索引时表上的非聚簇索引重建两次
CREATE CLUSTERED INDEX INDEX_NAME ON TABLE_NAME(COLUMN1) WITH(DROP_EXISTING=ON) --该方法有可能引起阻塞和索引的消失。
--显示指定的表或视图的数据和索引的碎片信息
DBCC SHOWCONTIG
DBCC SHOWCONTIG
[ (
{ table_name | table_id | view_name | view_id }
[ , index_name | index_id ]
) ]
[ WITH
{
[ , [ ALL_INDEXES ] ]
[ , [ TABLERESULTS ] ]
[ , [ FAST ] ]
[ , [ ALL_LEVELS ] ]
[ NO_INFOMSGS ]
}
]
--table_name | table_id | view_name | view_id
要检查碎片信息的表或视图。如果未指定,则检查当前数据库中的所有表和索引视图。若要获得表或视图 ID,请使用 OBJECT_ID 函数。
index_name | index_id
要检查碎片信息的索引。如果未指定,则该语句将处理指定表或视图的基本索引。若要获取索引 ID,请使用 sys.indexes 目录视图。
WITH
指定有关 DBCC 语句返回的信息类型的选项。
FAST
指定是否要对索引执行快速扫描和输出最少信息。快速扫描不读取索引的叶级或数据级页。
ALL_INDEXES
显示指定表和视图的所有索引的结果,即使指定了特定索引也是如此。
TABLERESULTS
将结果显示为含附加信息的行集。
ALL_LEVELS
仅为保持向后兼容性而保留。即使指定了 ALL_LEVELS,也只对索引叶级或表数据级进行处理。
NO_INFOMSGS
取消严重级别从 0 到 10 的所有信息性消息。
--分析:
扫描页数:
如果知道行的近似尺寸 和索引里的行数,即可估算出索引里的页数。如果扫描的页数明显大于估算的页数则存在内部碎片。
扫描的扩展盘区数:
扫描页数除以8(8K为一页)得到一个最高值。如果DBCC 扫描返回的数 高,则说明存在外部碎片。
扩展盘区开关数:
该数应该等于扫描扩展盘区数 -1 。如果高则存在外部碎片。
每个扩展盘区上的平均页数;
扫描页数 除以 被扫描扩展盘区数.一般为8 .如果小于 8则存在外部碎片。
扫描密度:
即 最佳值 :实际值 的比率.如果这个比率值过低说明存在外部碎片.这个值最好接近100%.越低越有问题.
逻辑扫描碎片:
即 无序页的百分比.最好将该值控制在10%以内.高了说明有外部碎片.
扩展盘区扫描碎片:
即 无序扩展盘区在扫描索引叶级别页中所占的百分比.如果百分比 高说明存在外部碎片。
平均页密度:
每页上的平均可用字节数的百分比的相反数。低的百分比说明 有内部碎片。
每页上的平均可用字节数:
指所扫描的页上的平均可用字节数。越高说明存在 内部碎片。
SELECT OBJECT_NAME(ind.OBJECT_ID) AS TableName,
ind.name AS IndexName, indexstats.index_type_desc AS IndexType,
indexstats.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) indexstats
INNER JOIN sys.indexes ind
ON ind.object_id = indexstats.object_id
AND ind.index_id = indexstats.index_id
WHERE OBJECT_NAME(ind.OBJECT_ID)='PRIMARYCODE'
ORDER BY indexstats.avg_fragmentation_in_percent DESC
sp_helpstats PRIMARYCODE
DBCC SHOW_STATISTICS(PRIMARYCODE,FWMAPPLYCODE)--查看统计信息
DBCC SHOWCONTIG (PRIMARYCODE,IDX_PRIMARYCODE_PRIMARYCODE)
IDX_PRIMARYCODE_PRIMARYCODE
PK__PRIMARYC__AA1D437813BCEBC1
IDX_PRIMARYCODE_FWMAPPLYCODE
SQLServer提供了一个数据库命令——DBCC SHOWCONTIG——来确定一个指定的表或索引是否有碎片。
示例:
显示数据库里所有索引的碎片信息
DBCC SHOWCONTIG WITH ALL_INDEXES
显示指定表的所有索引的碎片信息
DBCC SHOWCONTIG (authors) WITH ALL_INDEXES
显示指定索引的碎片信息
DBCC SHOWCONTIG (authors,aunmind)
DBCC 执行结果:
扫描页数:如果你知道行的近似尺寸和表或索引里的行数,那么你可以估计出索引里的页数。看看扫描页数,如果明显比你估计的页数要高,说明存在内部碎片。
扫描扩展盘区数:用扫描页数除以8,四舍五入到下一个最高值。该值应该和DBCC SHOWCONTIG返回的扫描扩展盘区数一致。如果DBCC SHOWCONTIG返回的数高,说明存在外部碎片。碎片的严重程度依赖于刚才显示的值比估计值高多少。
扩展盘区开关数:该数应该等于扫描扩展盘区数减1。高了则说明有外部碎片。
每个扩展盘区上的平均页数:该数是扫描页数除以扫描扩展盘区数,一般是8。小于8说明有外部碎片。
扫描密度[最佳值:实际值]:DBCC SHOWCONTIG返回最有用的一个百分比。这是扩展盘区的最佳值和实际值的比率。该百分比应该尽可能靠近100%。低了则说明有外部碎片。
逻辑扫描碎片:无序页的百分比。该百分比应该在0%到10%之间,高了则说明有外部碎片。
扩展盘区扫描碎片:无序扩展盘区在扫描索引叶级页中所占的百分比。该百分比应该是0%,高了则说明有外部碎片。
每页上的平均可用字节数:所扫描的页上的平均可用字节数。越高说明有内部碎片,不过在你用这个数字决定是否有内部碎片之前,应该考虑fill factor(填充因子)。
平均页密度(完整):每页上的平均可用字节数的百分比的相反数。低的百分比说明有内部碎片。
解决碎片问题 :
1. 删除并重建索引
2. 使用DROP_EXISTING子句重建索引
3. 执行DBCC DBREINDEX
4. 执行DBCC INDEXDEFRAG
删除并重建索引 :
用DROP INDEX和CREATE INDEX或ALTER TABLE来删除并重建索引有些缺陷包括在删除重建期间索引会消失。在索引删除重建时,对于查询它不在可用,查询性能也许会受到明显的影响,直到重建索引为止。另一个潜在的缺陷是当都请求索引的时候会引起阻塞,直到重建索引为止。通过其他的处理也能解决阻塞,就是索引被使用的时候不删除索引。另一个主要的缺陷是在用DROP INDEX和CREATE INDEX重建聚集索引时会引起非聚集索引重建两次。删除聚集索引时非聚集索引的行指针会指向数据堆,聚集索引重建时非聚集索引的行指针又会指回聚集索引的行位置。
删除并重建索引的确有一个好处就是通过重新排序索引页,使索引页紧凑并删除不需要的索引页来完全重建索引。你也许需要考虑那些内部和外部碎片都很高的情况下才使用,以使那些索引回到它们应该在的位置。
使用DROP_EXISTING子句重建索引 :
为了避免在重建聚集索引时表上的非聚集索引重建两次,可以使用带DROP_EXISTING子句的CREATE INDEX语句。这个子句会保留聚集索引键值,以避免非聚集索引重建两次。和删除并重建索引一样,该方法也可能会引起阻塞和索引消失的问题。该方法的另一个缺陷是也强迫你去分别发现和修复表上的每一个索引。
除了和上一个方法一样的好处之外,该方法的好处是不必重建非聚集索引两次。这样可以对那些带约束的索引提供正确的索引定义以符合约束的要求。
执行DBCC DBREINDEX :
DBCC DBREINDEX类似于第二种方法,但它物理地重建索引,允许SQLServer给索引分配新页来减少内部和外部碎片。DBCC DBREINDEX也能动态的重建带约束的索引,不象第二种方法。
DBCC DBREINDEX的缺陷是会遇到或引起阻塞问题。DBCC DBREINDEX是作为一个事务来运行的,所以如果在完成之前中断了,那么你会丢失所有已经执行过的碎片。
执行DBCC INDEXDEFRAG :
DBCC INDEXDEFRAG(在SQLServer2000中可用)按照索引键的逻辑顺序,通过重新整理索引里存在的叶页来减少外部碎片,通过压缩索引页里的行然后删除那些由此产生的不需要的页来减少内部碎片。它不会遇到阻塞问题但它的结果没有其他几个方法彻底。这是因为DBCC INDEXDEFRAG跳过了锁定的页且不使用任何新页来重新排序索引。如果索引的碎片数量大的话你也许会发现DBCC INDEXDEFRAG比重建索引花费的时间更长。DBCC INDEXDEFRAG比其他方法的确有好处的是在其他过程访问索引时也能进行碎片整理,不会引起其他方法的阻塞问题。
内部碎片:
指 当索引页没有用到最大量时就产生了内部碎片。虽然在一个有频繁数据插入的应用程序里这也许有帮助,然而设置一个fill factor(填充因子)会在索引页上留下空间,服务器内部碎片会导致索引尺寸增加,从而在返回需要的数据时要执行额外的读操作。这些额外的读操作会降低查询的性能
外部碎片;
指 表中的数据被修改会产生碎片。当插入或更新表中数据时,表的对应聚簇索引和受影响的聚簇索引被修改。如果对索引的修改不能容纳到同一个页面中,就可能导致索引叶子页面分割。这样就会有一个新的叶子页面被添加,该页面包含原来页面中的部分信息(通常是一半),并且维持索引键中的逻辑顺序。但是该页面通常不是与原来页面相邻的。这就产生了逻辑关键字顺序和文件中的物理顺序不一致。