提升全文索引的性能

适用于:SQL ServerAzure SQL 数据库Azure SQL 托管实例

本文涵盖了全文索引和查询性能不佳的常见原因,以及如何缓解这些问题。

性能问题的常见原因

本节介绍使用全文索引时常见的性能问题原因。

硬件资源问题

硬件资源如内存、磁盘速度、CPU速度和机器架构会影响全文索引和全文查询的性能。

硬件资源限制导致全文索引性能下降。

  • CPU。 如果过滤器守护进程(fdhost.exe)或SQL Server进程(sqlservr.exe)的CPU使用率接近100%,那么CPU就是瓶颈。

  • 内存。 物理记忆的短缺可能导致瓶颈。

  • 磁盘。 如果平均等待队列长度是磁盘头数的两倍以上,则磁盘存在瓶颈。 主要的解决方法是创建独立于 SQL Server 数据库文件和日志的全文目录。 将日志、数据库文件和全文目录分别放在不同的磁盘上。 安装运行速度更快的磁盘和使用 RAID 也能帮助改善索引性能。

全文批处理问题

如果系统没有硬件瓶颈,全文搜索的索引性能主要取决于以下因素:

  • 数据库引擎创建全文批处理所需的时间。

  • 过滤守护进程处理这些批数据的速度。

全文索引填充问题

  • 填充类型。 与完全填充不同,增量、手动和自动更改跟踪填充并非旨在最大化硬件资源以实现更快速度。 因此,本文中的调优建议在使用增量、手动或自动变更跟踪人口时,可能无法提升全文索引的性能。

  • 主服务器合并。 当一个批次完成后,最终会通过合并过程将各个索引片段整合为一个 主 全文索引。 这一过程提高了查询性能,因为只需查询 主 索引,而不需要查询多个索引片段。 更好的评分统计数据可能会用于相关性排名。 然而,主合并操作可能会产生大量 I/O 开销,因为在合并索引片段时必须写入和读取大量数据。 不过,它不会阻止收到的查询。

    主合并大量数据可能会创建长运行事务,延迟检查点期间事务日志的截断。 在这种情况下,事务日志可能会在完整恢复模式下显著增长。 作为最佳做法,在使用完整恢复模式的数据库中重新组织较大的全文索引之前,应确保事务日志中包含足够的空间用于长时间运行的事务。 有关详细信息,请参阅管理事务日志文件的大小。

优化全文索引的性能

若要最大限度地提高全文索引的性能,请实施下列最佳做法:

  • 要最大化使用所有CPU核心,将系统核心数更改 max full-text crawl range 为。 更多信息请参见 服务器配置:最大全文爬取范围。

  • 请确保基表具有聚集索引。 对聚集索引的第一列使用整数数据类型。 避免在聚集索引的第一列使用 GUID。 对聚集索引执行多范围填充可以产生最高的填充速度。 将用作全文键的列的数据类型设为整数类型。

  • 使用 UPDATE STATISTICS 语句更新基表的统计信息。 更重要的是,更新聚集索引或全文键的统计信息以进行完全填充。 此操作有助于多区间种群在表上生成良好的分区。

  • 在大型多核计算机上执行完全填充之前,通过将 max server memory 值设置为保留足够内存供 fdhost.exe 进程和操作系统使用,暂时限制缓冲池大小。 欲了解更多信息,请参见本文后面的 “估计滤波守护进程fdhost.exe()的内存需求”。

  • 如果使用基于时间戳列的增量填充,请对 timestamp 列生成辅助索引来提高增量填充的性能。

排查完全填充性能问题

请参阅以下部分以解决完全填充的性能问题。

查看全文爬网日志

为了帮助诊断性能问题,请查看全文爬行日志。

如果在爬网期间发生了错误,全文搜索的爬网日志功能会创建并维护一个爬网日志,该日志是一个纯文本文件。 每个爬网日志都对应于某一个全文目录。 默认情况下,给定实例(在此示例中为默认实例)的爬网日志文件位于 %ProgramFiles%\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\LOG 文件夹中。

爬网日志文件遵循以下命名方案:

SQLFT<DatabaseID><FullTextCatalogID>.[<n>]

爬网日志文件名的可变部分如下。

  • <DatabaseID>:数据库的ID,作为一个带前零的五位数字。

  • <FullTextCatalogID>:全文目录 ID,为带前导零的五位数。

  • <n>: 一个整数表示存在一个或多个同一全文目录的爬取日志。

例如,SQLFT0000500008.2 是一个数据库 ID 为 5、全文目录 ID 为 8 的数据库爬网日志文件。 文件名结尾的 2 指示此数据库/目录对具有两个爬网日志文件。

检查物理内存用量

在进行全文填充期间,fdhost.exe 或 sqlservr.exe 进程可能会内存不足,甚至耗尽内存。

  • 如果全文爬取日志显示频繁 fdhost.exe 重启或返回错误代码8007008,说明其中一个进程内存不足。

  • 如果 fdhost.exe 产生转储,特别是在大型多核系统上,可能是内存不足。

  • 有关全文爬行使用的内存缓冲区信息,请参见 sys.dm_fts_memory_buffers。

导致内存不足或内存不足问题的可能原因包括以下几项:

  • 内存不足。 如果在满人口期间可用的物理内存为零,数据库引擎缓冲池可能正在占用系统上大部分物理内存。

    sqlservr.exe 进程试图侵占缓冲池的所有可用内存(最大为配置的最大服务器内存)。 如果为 max server memory 分配的内存过大,则 fdhost.exe 进程可能会发生内存不足,并且无法分配共享内存。

    适当设置 max server memory 数据库引擎 缓冲池的值以解决这个问题。 欲了解更多信息,请参见本文后面的 “估计滤波守护进程fdhost.exe()的内存需求”。 减少用于全文索引的批量规模也可能有所帮助。

  • 内存争用。 在多核系统上的全文填充期间,fdhost.exe 和 sqlservr.exe 会争用缓冲池内存。 由此导致的共享内存缺乏会引起批重试、内存抖动以及 fdhost.exe 进程转储。

  • 分页问题。 页面文件大小不足(例如在页面文件较小且增长受限的系统上)也可能导致 fdhost.exe 或 sqlservr.exe 进程内存耗尽。 如果爬取日志没有显示任何内存相关的故障,过度分页很可能导致了性能变慢。

估算滤波守护进程主机进程的内存需求(fdhost.exe)

进程用于填充所需的内存 fdhost.exe 量主要取决于其使用的全文爬取范围数量、入站共享内存(ISM)的大小以及最大ISM实例数。

你可以用以下公式大致估算滤波守护进程主机的内存消耗:

number_of_crawl_ranges * ism_size * max_outstanding_isms * 2

上述公式中变量的默认值如下:

变量 默认值
number_of_crawl_ranges CPU 核心数
ism_size 适用于 x86 计算机的 1 MB

x64 计算机的内存容量为 4 MB、8 MB 或 16 MB,具体取决于总物理内存
max_outstanding_isms 适用于 x86 计算机的 25

5 适用于 x64 计算机

下表提供了估算 的 fdhost.exe内存需求指南。 此表中的公式使用以下值:

  • F,是所需的 fdhost.exe 内存估计值(单位为MB)。

  • T,它是系统中可用物理内存的总量(以 MB 为单位)。

  • M,这是最优 max server memory 设置。

有关以下公式的基本信息,请参阅表后面的说明。

平台 估计 fdhost.exe 内存需求(MB): F^1 计算最大服务器内存的公式: M^2
x86 F = 爬取范围的数量 * 50 M = 最小值(T, 2000) - F - 500
x64 F = 爬取范围的数量 * 10 * 8 M = T - F - 500
  1. 如果有多个完整群体正在进行中,分别计算 fdhost.exe 每个群体的内存需求,如 F1、 F2等。 然后计算 M 为 T - Σ(Fi)。

  2. 500 MB 是系统中其他进程所需内存的估计值。 如果系统正在执行其他工作,请相应地增加此值。

  3. 对于x64平台,假设ism_size为8 MB。

示例:估算fdhost.exe的内存需求

这个例子是针对一台64位计算机,配备8GB内存和4颗双核处理器。 第一个计算估计了 fdhost.exe 所需的内存。爬行范围的数量为 8。

F = 8 * 10 * 8 = 640

下一次计算得到 (max server memory) 的最优值。 该系统的总物理内存(以 MB 为单位,T)为 8192。

M = 8192 - 640 - 500 = 7052

示例:Set max server memory

本示例使用 sp_configure 和 RECONFIGURE Transact-SQL 语句,将 max server memory 设置为前面示例中为 M 计算出的值7052:

USE master;
GO

EXECUTE sp_configure 'max server memory', 7052;
GO

RECONFIGURE;
GO

有关服务器内存选项的更多信息,请参见 服务器内存配置选项。

检查 CPU 使用率

当平均CPU占用率低于约30%时,满群体的性能并不理想。 本部分讨论影响 CPU 占用率的一些因素。

  • 页面等待时间过长

    要了解等待页面的时间是否太长,请运行以下 Transact-SQL 语句:

    SELECT TOP 10 *
    FROM sys.dm_os_wait_stats
    ORDER BY wait_time_ms DESC;
    

    下表描述了感兴趣的等待类型。

    等待类型 说明 可能的解决方法
    PAGEIO_LATCH_SH(_EX 或 _UP) 这种等待类型可能表明存在I/O瓶颈,这种情况下通常还会看到较高的平均磁盘队列长度。 将全文索引迁移到不同磁盘上的另一个文件组,可能有助于减少I/O瓶颈。
    PAGELATCH_EX (或 _UP) 这种等待类型可能表明试图写入同一数据库文件的线程之间存在大量争用。 将文件添加到全文索引所在的文件组中,有助于缓解这种争夺。

    有关详细信息,请参阅 sys.dm_os_wait_stats。

  • 扫描基表的效率很低

    完全填充将扫描基表,以生成批次。 在以下情况下,这种表扫描可能效率低下:

    • 如果基表有很高百分比的行外列正在建立全文索引,则扫描基表以生成批次可能成为瓶颈。 在这种情况下,通过使用 varchar(max) 或 nvarchar(max) 来将较小的数据移入行,可能会有帮助。

    • 如果基表非常零碎,扫描可能很低效。 有关如何计算行外数据和索引碎片的信息,请参见 sys.dm_db_partition_stats 和 sys.dm_db_index_physical_stats。

      若要减少碎片,可以重新组织或重新生成聚集索引。 有关详细信息,请参阅 优化索引维护以提高查询性能并减少资源消耗。

排查文档索引编制缓慢的问题

注意

本部分所述的问题只会影响对嵌入其他文档类型的文档(例如 Microsoft Word 文档)编制索引的客户。

填充全文索引时,全文引擎使用两种类型的筛选器:多线程筛选器和单线程筛选器。

  • 一些文档,如Word文档,使用多线程过滤器。
  • 其他文档,如Adobe Acrobat便携文档格式(PDF)文档,则使用单线程过滤器。

为了安全起见,筛选器是由筛选器后台程序主机进程加载的。 服务器实例对所有多线程筛选器使用多线程进程,并对所有单线程筛选器使用单线程进程。 如果使用多线程筛选器的文档包含使用单线程筛选器的嵌入文档,全文引擎将启动单线程进程以处理嵌入文档。 例如,在遇到包含 PDF 文档的 Word 文档时,全文引擎使用多线程进程来处理 Word 内容,并启动单线程进程以处理 PDF 内容。 然而,单线程滤波器可能在这种环境下表现不佳,可能会使过滤过程不稳定。

在某些此类嵌入较为常见的情况下,失稳可能会导致该进程崩溃。 当出现这种情况时,Full-Text 引擎会将任何失败的文档(例如包含嵌入PDF内容的Word文档)重新路由到单线程过滤过程。 如果频繁进行重新传送,将会导致全文索引进程性能下降。

为了解决这个问题,可以将容器文档(本例中的 Word 文档)的过滤器标记为单线程过滤器。 要将滤波器标记为单线程滤波器,将滤波ThreadingModel器的注册表值设置为 Apartment Threaded 。 有关单线程单元的信息,请参阅理解和使用 COM 线程模型。