SQL Server 全文索引的管理

全文索引不同于常见的聚集索引或非聚集索引,这些索引的内部实现是平衡树(B-Tree)结构,而全文索引在物理上是由一系列的内部表(Internal tables)构成的,这些内部表称作全文索引片段(Fragment),每一个索引片段也叫做一个倒转索引(Inverted index),也就是说,每一个倒转索引都是由一个内部表(Internal Table)实现的。

有一些好奇的朋友可能会发问:“为什么一个全文索引是由一系列的倒转索引构成的,而不是一个?为什么叫做倒转索引,把什么倒转了?”

当新建全文索引之后,全文索引只有一个索引片段(Fragment),索引片段中没有冗余的数据,从全文索引中执行contains命令时,只需要从这一个倒转索引中查找,返回结果即可。随着业务数据的更新,基础表(underlying table)的数据也会更新,这时,全文索引会创建新的倒转索引,但是,旧的数据没有被删除,这样会导致倒转索引的数量增加,也就是说,全文索引的片段增加,此时,全文索引就是由一系列的索引片段构成的。当全文索引的片段持续增多时,从全文索引中进行文本搜索需要查找更多的数据行,导致全文搜索的性能下降。在管理全文索引时,必须对索引片段进行重组(reorganize)或重建(rebuild),把已删除的数据从索引片段中物理删除,减少全文索引的片段数量,提高全文搜索的性能。

至于为什么称作倒转索引,这跟倒转索引存储的数据有关。

一,倒转索引的结构

为了便于描述,把全文索引中存储的一行数据叫做一个文档,每一个文档都使用唯一的文档ID(DocID)标识,这个DocID也就是在创建全文索引之前,必须创建的唯一索引键。

大家知道,全文索引中存储的不是整个文本,而是把文本分词之后,存储单个标记(Token)的信息,标记(Token)是分词,及其位置等信息的统称。在填充全文索引的时候,分词器(word breader)将字符串拆分成多个单词。如果单词是一个停用词(stopword),那么该分词被过滤掉,不会存储到倒转索引中,但是停用词的位置(position)会被考虑,一个分词在全文索引中的位置(Position)是该分词在源文本中的位置。简而言之,倒转索引中存储的数据是分词和DocID之间的映射。

由DocID来查询分词,是正向的;而由分词来定位DocID,是倒转的,这就是倒转索引名称的由来。

例如,一个基础表Document有两列,DocumentID和Title,在字段Title上创建全文索引:

全文引擎首先要对Title字段的文本进行分词,倒转索引中主要包含四个字段:

  • Keyword字段:单个分词,从Title字段中抽取的一个标记(Token)。
  • ColId字段:列序号,用于标记全文索引的列。
  • DocId字段:文档ID,是8Byte的long类型,用于唯一标记当前的文档。如果唯一索引键是整数类型,那么DocID就是唯一索引键;如果唯一索引键不是整数类型,那么DocID经过中间的映射表、唯一映射到唯一索引键。因此,整数类型的唯一索引键能够优化全文查询的性能。
  • Occurrence字段:分词的位置,或者叫做偏移量(Offset)。
  • CreateTime字段:时间戳字段(timestamp ),用于记录倒转索引创建的时间。

例如,下图是Document表的索引片段Fragment1:

对于DocumentID=1的文档,分词器把Title字段拆分成5个分词,这5个分词分别是:Crank、Arm、and、Tire、Maintenance,出现的位置分别是1,2,3,4,5,由于分词and是一个停用词,过滤器会把分词and过滤掉,但是and分词的位置会计算在后续的分词上。因此,分词Tire的位置(Occurrence)是4,而不是3。

二,全文索引的拆分

全文索引通常会拆分成多个索引片段,一些索引片段可能包含新的数据,而一些索引片段可能包含已经被删除的数据。例如,如果有一个用户把DocumentID=3的文档的Title字段更新为Rear Reflector:

全文索引会新建一个索引片段Fragmeng2,如下图所示,

因此,如果有用户查询"Rear Reflector" ,DocID3将会被返回。每一个Fragment都会记录创建的时间,当相同的DocID出现在不同的索引片段中,创建时间晚的是最新的数据。索引片段的创建时间可以从系统视图:sys.fulltext_index_fragments 中查看。

三,全文索引片段的重组

当数据持续更新时,索引片段的数量也会持续增加,而全文查询必须首先搜索每一个索引片段,然后丢弃无用的老数据,这会导致全文查询的性能下降,必须减少索引片段的数量。由于每一个全文索引都属于一个全文目录(fulltext catalog),SQL Server使用TSQL 命令 ALTER FULLTEXT CATALOG  和REORGANIZE 选项对目录中的所有全文索引进行重组操作。

SQL Server使用master merge来重组全文索引,也就是说,把全文索引的各个索引片段归并到一个打的片段中,然后把废弃的文档从全文索引中删除,这样重组之后,全文索引中包含的都是纯净的数据:

四,配置全文索引的停用词

为了阻止全文索引把停用词填充到全文索引中,SQL Server允许用户自定义停用词列表,把常用词(这些词对查询没有任何帮助)添加到停用词列表中。在填充全文索引时,全文引擎会把停用词过滤掉,这意味着,全文查询不会搜索停用词,尽管全文索引会忽略停用词,但是,停用词的位置会被考虑进去,每个分词的位置是该分词在源文本中的偏移量。

通过 CREATE FULLTEXT STOPLIST (Transact-SQL) 创建停用词列表(StopLists),通过ALTER FULLTEXT STOPLIST (Transact-SQL) 向停用词列表中增加和删除停用词(Stopword),通过ALTER FULLTEXT INDEX (Transact-SQL) 更新全文索引引用的停用词列表,实例代码如下:

CREATE FULLTEXT STOPLIST stoplist_name
FROM SYSTEM STOPLIST;

ALTER FULLTEXT STOPLIST stoplist_name
ADD ‘stopword‘ LANGUAGE language_term;

ALTER FULLTEXT INDEX
ON table_name
SET STOPLIST =stoplist_name
[WITH NO POPULATION];

五,查看分词

分词是全文引擎的一项重要的功能,通过 sys.dm_fts_parser 可以分词器对文本分词之后的结果,这也可以用于查看contains 子句产生的分词:

sys.dm_fts_parser(‘query_string‘, lcid, stoplist_id, accent_sensitivity)

1,查看语句的分词

SELECT fp.keyword,
    fp.group_id,
    fp.phrase_id,
    fp.occurrence,
    fp.special_term,
    fp.display_term,
    case fp.expansion_type
        when 0 then N‘Single word case‘
        when 2 then N‘Inflectional expansion‘
        when 4 then N‘Thesaurus expansion/replacement‘
    end as expansion_type,
    fp.source_term
FROM sys.dm_fts_parser (‘ "The Microsoft business analysis" or "MS revenue" or "multi-million" ‘, 1033, 0, 0) as fp

2,查看contains 谓词如何解析 FORMSOF 子句

查看同源词,  ‘query_string‘ 的格式是: ‘FORMSOF( INFLECTIONAL, query_term )‘

SELECT fp.keyword,
    fp.group_id,
    fp.phrase_id,
    fp.occurrence,
    fp.special_term,
    fp.display_term,
    case fp.expansion_type
        when 0 then N‘Single word case‘
        when 2 then N‘Inflectional expansion‘
        when 4 then N‘Thesaurus expansion/replacement‘
    end as expansion_type,
    fp.source_term
FROM sys.dm_fts_parser (‘FORMSOF(INFLECTIONAL,run ) ‘, 1033, 0, 0) as fp

查看同义词,  ‘query_string‘  的格式是: ‘FORMSOF( THESAURUS, query_term )‘

SELECT fp.keyword,
    fp.group_id,
    fp.phrase_id,
    fp.occurrence,
    fp.special_term,
    fp.display_term,
    case fp.expansion_type
        when 0 then N‘Single word case‘
        when 2 then N‘Inflectional expansion‘
        when 4 then N‘Thesaurus expansion/replacement‘
    end as expansion_type,
    fp.source_term
FROM sys.dm_fts_parser (‘FORMSOF(THESAURUS,run ) ‘, 1033, 0, 0) as fp

六,查看全文索引的元数据

1,查看数据库中的全文索引

select
    object_name(i.object_id) as TableName,
    i.unique_index_id,
    i.fulltext_catalog_id,
    c.name as fulltext_catalog_name,
    i.is_enabled,
    i.change_tracking_state_desc,
    i.crawl_type_desc,
    i.has_crawl_completed,
    iif(i.has_crawl_completed=1,datediff(minute,i.crawl_start_date,i.crawl_end_date),0) as crawl_duration_minute,
    i.crawl_start_date,
    i.crawl_end_date,
    i.incremental_timestamp,
    i.stoplist_id,
    i.data_space_id,
    ds.name as data_space_Name,
    ds.type_desc as data_sapce_type
from  sys.fulltext_indexes i
inner join sys.data_spaces ds
    on i.data_space_id=ds.data_space_id
inner join sys.fulltext_catalogs c
    on i.fulltext_catalog_id=c.fulltext_catalog_id

2,查看全文索引的所有分词

declare @db_id int
declare @table_id int 

set @db_id=db_id()
set @table_id=object_id(N‘schema_name.table_name‘,N‘U‘)

select kw.keyword,
    kw.display_term,
    kw.column_id,
    kw.document_count
from sys.dm_fts_index_keywords(@db_id,@table_id) as kw

3,查看当个文档的分词

declare @db_id int
declare @table_id int 

set @db_id=db_id()
set @table_id=object_id(N‘meetup.Events‘,N‘U‘)

select kw.keyword,
    kw.display_term,
    kw.column_id,
    kw.document_id,
    kw.occurrence_count
from sys.dm_fts_index_keywords_by_document(@db_id,@table_id) as kw

4,查看全文索引的内部表(Internal Tables)

SELECT SCHEMA_NAME(itab.schema_id) AS [schema]
    ,itab.name AS internal_table_name
    ,typ.name AS column_data_type
    ,col.name as column_name
    ,col.column_id
    ,OBJECT_NAME(itab.parent_object_id) as base_table_name
FROM sys.internal_tables AS itab
INNER JOIN sys.columns AS col ON itab.object_id = col.object_id
INNER JOIN sys.types AS typ ON typ.user_type_id = col.user_type_id
where itab.internal_type_desc=N‘FULLTEXT_COMP_FRAGMENT‘
ORDER BY itab.name, col.column_id;

5,查看每一个倒转索引的大小和包含的数据行数

select object_name(table_id) as base_table_name,
    object_name(fragment_object_id) as fragment_table_name,
    fragment_id as Ordinal,
    status,
    data_size,
    row_count,
    [timestamp]
from sys.fulltext_index_fragments

字段 Status 表示索引片段的状态:

  • 0 = Newly created and not yet used
  • 1 = Being used for insert during fulltext index population or merge
  • 4 = Closed. Ready for query
  • 6 = Being used for merge input and ready for query
  • 8 = Marked for deletion. Will not be used for query and merge source.

当状态值为4或6时,表示索引片段已经是全文索引的一部分,可以被查询,字段Timestamp表示该索引片段创建的时间戳,时间较晚的索引碎片中存储的是最新的数据,而时间较早的索引片段中存储的是被删除/淘汰的数据。在执行全文查询时,返回的结果中会丢弃被淘汰的数据。

参考文档:

Create and Manage Full-Text Indexes

Manage Full-Text Indexes

Improve the Performance of Full-Text Indexes

sys.dm_fts_parser (Transact-SQL)

原文地址:https://www.cnblogs.com/ljhdo/p/5540239.html

时间: 2024-10-29 19:10:29

SQL Server 全文索引的管理的相关文章

《SQL Server企业级平台管理实践》读书笔记——SQL Server如何设置自动增长和自动收缩项

原文:<SQL Server企业级平台管理实践>读书笔记--SQL Server如何设置自动增长和自动收缩项 SQL Server允许用户设置数据库初始值和最大值,可以通过自动增长或者自动收缩进行配置.通过这些配置,我们可以防止数据库空间问题而导致的应用程序修改失败或者SQL Server磁盘空间耗尽的事情发生.一般来讲,如果数据库不是很忙,默认的设置为自动增长,这种方式能够满足大部分的需求.但是在大量并发的情况下,申请数据文件和日志文件增长本身是一件非常消耗系统资源和影响性能的工作.所以如果

[译]SQL Passion Week 3: SQL Server的扇区管理

SQL Passion Week 3: SQL Server的扇区管理 混合扇区和统一扇区 SQL Server中每8个数据页作为一个扇区. 在混合扇区中, 其包含的8个页可以分别属于不同的数据库对象; 另一方面, 统一扇区里的8个页都属于同一个数据库对象. 为什么有这样一个区别呢, 这其实主要是因为一个历史遗留问题.  因为在上个世纪, 存储是非常昂贵的, 人们会尽可能有效的充分利用存储空间. 当一个表和索引最初创建时, 总是创建在一个混合扇区上, 先在8kb的空间里进行增长. 这样, 小的表

《SQL Server企业级平台管理实践》读书笔记——SQL Server中收缩数据库不好用的原因

原文:<SQL Server企业级平台管理实践>读书笔记--SQL Server中收缩数据库不好用的原因 数据库管理员有时候需要控制文件的大小,可能选择收缩文件,或者把某些数据文件情况以便从数据库里删除. 这时候我们就要使用到DBCC SHRINKFILE命令,此命令的脚本为: DBCC SHRINKFILE ( { file_name | file_id } { [ , EMPTYFILE ] | [ [ , target_size ] [ , { NOTRUNCATE | TRUNCATE

《SQL Server企业级平台管理实践》读书笔记——SQL Server数据库文件分配方式

原文:<SQL Server企业级平台管理实践>读书笔记--SQL Server数据库文件分配方式 1.文件分配方式以及文件空间检查方法 最常用的检查数据文件和表大小的命令就是:sp_spaceused 此命令有三个缺陷:1.无法直观的看出每个数据文件和日志文件的使用情况.2.这个存储过程依赖SQL Server存储在一些系统视图里的空间使用统计信息计算出的结果,如果没有更新空间统计信息,比如刚刚发生大数据插入,sp_spaceused的结果就不准确.3.这个命令主要是针对普通用户的数据库,对

《SQL Server企业级平台管理实践》读书笔记——几个系统库的备份与恢复

原文:<SQL Server企业级平台管理实践>读书笔记--几个系统库的备份与恢复 master数据库 master作为数据库的主要数据库,记录着SQL Server系统的所有系统级信息,例如登录用户.系统配置设置.端点和凭证以及访问其他数据服务器所需要的信息.master数据库还记录着启动服务器实例所需要的初始化信息,每个其它数据库的主文件位置.master数据库是SQL Server启动的时候打开的第一个数据库.SQL Server是从这个数据库里找到其它数据的信息的.如果master数据

SQL Server 表的管理_关于表的操作增删查改的操作的详解(案例代码)

SQL Server 表的管理_关于表的操作增删查改的操作的详解(案例代码) 概述: 表由行和列组成,每个表都必须有个表名. SQL CREATE TABLE 语法 CREATE TABLE table_name ( column_name1 data_type(size), column_name2 data_type(size), column_name3 data_type(size), .... ); 1.查看表 exec sp_help table1; 2.创建表 create tab

[MS-SQL] SQL Server 2008 组态管理工具出现:远端进程调用失败 0x800706be 解决方法

[MS-SQL] SQL Server 2008 管理工具出现"远端进程调用失败 0x800706be"解决方法 因为项目需求电脑装的 SQL Server 是使用 SQL Server 2008 Express 版本,而自从安装完 VS 2012 之后原本正常的 SQL Server 竟然立马坏了,又因为时间总是太少事情总是太多,所以一直拖到最近才来找问题,不要问我那我工作怎办!因为至少 SQL 连远端的部分还是正常的! 问题由来 因为项目需求电脑装的 SQL Server 是使用

SQL Server 全文索引介绍(转载)

概述 全文引擎使用全文索引中的信息来编译可快速搜索表中的特定词或词组的全文查询.全文索引将有关重要的词及其位置的信息存储在数据库表的一列或多列中.全文索引是一种特殊类型的基于标记的功能性索引,它是由 SQL Server 全文引擎生成和维护的.生成全文索引的过程不同于生成其他类型的索引.全文引擎并非基于特定行中存储的值来构造 B 树结构,而是基于要编制索引的文本中的各个标记来生成倒排.堆积且压缩的索引结构.在 SQL Server 2008 中,全文索引大小仅受运行 SQL Server 实例的

SQL Server数据库空间管理 (1)

数据库经常遇到的问题: 1).数据库文件空间用尽  2).日志文件不停增长 3).数据库文件无法收缩  4).自动增长和自动收缩 本系列就以上面的4个问题入手分析并总结数据库空间的管理方法.   1.文件的分配方式以及文件空间检查方法 首先,你在你的数据库中运行sp_spaceused;之后会看到当前数据库的使用空间信息:这个命令也就会将大概的数据库空间信息给你展现出来,并不能查看每个数据文件和日志文件的使用情况:其中对于数据库tempdb来说里面存储的临时数据对象,这个命令是统计不到的.我们知