全文索引维护准则


29

维护全文索引应考虑哪些准则?

我应该重新构建或重新组织全文目录(请参阅BOL)吗?什么是合理的维护节奏?可以使用什么启发式方法(类似于10%和30%的碎片阈值)来确定何时需要维护?

(下面的所有内容只是有关此问题的详尽信息,并显示了我到目前为止的想法。)



额外信息:我的初步研究

有关b树索引维护的资源很多(例如,该问题Ola Hallengren的脚本以及其他站点上有关该主题的大量博客文章)。但是,我发现这些资源都没有提供用于维护全文索引的建议或脚本。

微软的文档是提到整理基表的B树索引,然后对全文目录执行REORGANIZE可以提高性能,但它并没有任何更具体的建议碰。

我也发现了这个问题,但它主要集中在变更跟踪(如何将对基础表的数据更新传播到全文索引中),而不是可以最大程度地提高索引效率的定期维护类型。

额外信息:基本性能测试

SQL Fiddle包含可用于创建具有AUTO更改跟踪的全文本索引的代码,并在修改表中的数据时检查索引的大小和查询性能。当我在生产数据的副本(而不是小提琴中的人造数据)上运行脚本的逻辑时,以下是在每个数据修改步骤之后看到的结果的摘要:

在此处输入图片说明

即使此脚本中的update语句设计得相当不错,但这些数据似乎表明定期维护有很多好处。

额外信息:初步构想

我正在考虑创建每晚或每周的任务。看来此任务可以执行REBUILD或REORGANIZE。

因为全文索引可能非常大(数以千万计的行),所以我希望能够检测目录中的索引何时足够零散,以确保需要进行REBUILD / REORGANIZE。对于哪种启发式方法可能有意义,我还不清楚。

Answers:


36

我无法在网上找到任何好的资源,因此我进行了一些动手研究,并认为发布根据我们的研究结果正在实施的全文维护计划会很有用。


我们的启发式方法确定何时需要维护

在此处输入图片说明

我们的主要目标是随着基础表中数据的发展而保持一致的全文查询性能。但是,由于种种原因,对于我们来说,每晚都很难对我们的每个数据库发起具有代表性的全文查询套件,并利用这些查询的性能来确定何时需要维护。因此,我们希望创建可以快速计算的经验法则,并将其用作启发式方法,以表明可能需要对全文索引进行维护。

在探索的过程中,我们发现系统目录提供了许多有关如何将给定的全文本索引分为多个片段的信息。但是,没有计算官方的“碎片百分比”(就像通过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提供了REBUILDREORGANIZE选项,但它们仅可用于全文目录(其中可能包含任意数量的全文索引)完整。由于遗留原因,我们有一个包含所有全文索引的全文目录。因此,我们选择删除(DROP FULLTEXT INDEX),然后CREATE FULLTEXT INDEX在单个全文索引级别上重新创建()。

最好以逻辑方式将全文索引分成单独的目录,然后执行REBUILD替代操作,但同时放置/创建解决方案将对我们有用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.