我无法在网上找到任何好的资源,因此我进行了一些动手研究,并认为发布根据我们的研究结果正在实施的全文维护计划会很有用。
我们的启发式方法确定何时需要维护
我们的主要目标是随着基础表中数据的发展而保持一致的全文查询性能。但是,由于种种原因,对于我们来说,每晚都很难对我们的每个数据库发起具有代表性的全文查询套件,并利用这些查询的性能来确定何时需要维护。因此,我们希望创建可以快速计算的经验法则,并将其用作启发式方法,以表明可能需要对全文索引进行维护。
在探索的过程中,我们发现系统目录提供了许多有关如何将给定的全文本索引分为多个片段的信息。但是,没有计算官方的“碎片百分比”(就像通过sys.dm_db_index_physical_stats的 b树索引一样)。基于全文片段信息,我们决定计算自己的“全文片段%”。然后,我们使用开发服务器反复对100到25,000行之间的任意位置重复进行一次随机更新,以更新到生产数据的1000万行,记录全文碎片,并使用进行基准全文查询CONTAINSTABLE
。
如上图和下图所示,结果非常有启发性,表明我们创建的碎片测量与观察到的性能高度相关。由于这也与我们在生产中的定性观察相联系,因此足以让我们满意地使用碎片百分比作为启发式方法来确定何时需要维护全文索引。
维修计划
我们已决定使用以下代码为每个全文本索引计算碎片百分比。任何不重要的,全文大小至少为10%的全文索引都将标记为由我们的通宵维护人员重新构建。
-- Compute fragmentation information for all full-text indexes on the database
SELECT c.fulltext_catalog_id, c.name AS fulltext_catalog_name, i.change_tracking_state,
i.object_id, OBJECT_SCHEMA_NAME(i.object_id) + '.' + OBJECT_NAME(i.object_id) AS object_name,
f.num_fragments, f.fulltext_mb, f.largest_fragment_mb,
100.0 * (f.fulltext_mb - f.largest_fragment_mb) / NULLIF(f.fulltext_mb, 0) AS fulltext_fragmentation_in_percent
INTO #fulltextFragmentationDetails
FROM sys.fulltext_catalogs c
JOIN sys.fulltext_indexes i
ON i.fulltext_catalog_id = c.fulltext_catalog_id
JOIN (
-- Compute fragment data for each table with a full-text index
SELECT table_id,
COUNT(*) AS num_fragments,
CONVERT(DECIMAL(9,2), SUM(data_size/(1024.*1024.))) AS fulltext_mb,
CONVERT(DECIMAL(9,2), MAX(data_size/(1024.*1024.))) AS largest_fragment_mb
FROM sys.fulltext_index_fragments
GROUP BY table_id
) f
ON f.table_id = i.object_id
-- Apply a basic heuristic to determine any full-text indexes that are "too fragmented"
-- We have chosen the 10% threshold based on performance benchmarking on our own data
-- Our over-night maintenance will then drop and re-create any such indexes
SELECT *
FROM #fulltextFragmentationDetails
WHERE fulltext_fragmentation_in_percent >= 10
AND fulltext_mb >= 1 -- No need to bother with indexes of trivial size
这些查询产生的结果如下所示,在这种情况下,第1、6和9行将被标记为过于分散,无法获得最佳性能,因为全文索引超过1MB,并且至少有10%分散。
维修节奏
我们已经有一个每晚维护时段,并且碎片计算的计算成本非常低。因此,我们将每晚运行一次此检查,然后仅在需要时才根据10%的碎片阈值执行实际重建全文索引的更昂贵的操作。
重建vs.重新组织vs.删除/创建
SQL Server提供了REBUILD
和REORGANIZE
选项,但它们仅可用于全文目录(其中可能包含任意数量的全文索引)完整。由于遗留原因,我们有一个包含所有全文索引的全文目录。因此,我们选择删除(DROP FULLTEXT INDEX
),然后CREATE FULLTEXT INDEX
在单个全文索引级别上重新创建()。
最好以逻辑方式将全文索引分成单独的目录,然后执行REBUILD
替代操作,但同时放置/创建解决方案将对我们有用。