SQL Server全文搜索(转载)

看这篇文章之前请先看一下下面我摘抄的全文搜索的MSDN资料,基本上MSDN上关于全文搜索的资料的我都copy下来了
并且非常认真地阅读和试验了一次,并且补充了一些SQL语句,这篇文章本人抽取了一些本人自认为是重点的出来
并且加入了一些自己的内容,补充MSDN上没有的和整理了网上关于全文搜索的资料
至于全文搜索的性能,注意事项,大家可以看我copy下来的文章
文章地址:http://www.cnblogs.com/lyhabc/articles/3254782.html
网上另一篇说全文搜索的也比较详细
SQL Server 全文目录相关 地址:http://www.cnblogs.com/dreamontheway/archive/2010/08/19/1809963.html
至于什么是全文搜索我就不说了,网上文章非常多,但是这些文章感觉总结和归纳不全,只是建立一下全文索引,但是并没有深入一些或者再整理一下
http://msdn.microsoft.com/zh-cn/library/ms142571.aspx
http://msdn.microsoft.com/zh-cn/library/ms142497.aspx
http://msdn.microsoft.com/zh-cn/library/ms142575.aspx
http://msdn.microsoft.com/zh-cn/library/ms142560.aspx
http://msdn.microsoft.com/zh-cn/library/cc879261(v=SQL.105).aspx
http://msdn.microsoft.com/zh-cn/library/ms142505(v=SQL.105).aspx


全文搜索的架构

先上MSDN的一幅图片

我画了一幅简单的图

所以从这个图上我们可以看到,一个数据库可以有多个全文目录,全文索引都存在于全文目录下,数据库中的每张表只能有一个全文索引。

其实全文搜索技术也有些人叫全文搜索或者叫全文索引,不过两种叫法本人都觉得是对的
MSDN中对于普通SQLSERVER和全文索引的区别

全文索引

普通 SQL Server 索引

每个表只允许有一个全文索引。

每个表允许有多个普通索引。

将数据添加到全文索引的操作称为“填充”,可以通过计划或特定请求来请求填充,也可以在添加新数据时自动填充。

当插入、更新或删除作为其基础的数据时自动更新。

在同一个数据库内分组为一个或多个全文目录。

不分组。

在一张表中建立了全文索引后,你不会看到数据表中会有全文索引页面,因为MSDN说得很清楚,
因为全文索引的行以压缩格式存储在磁盘的文件系统里,以优化磁盘的使用,并且这些数据会以二进制

创建全文目录的时候会有一个选项叫你选择目录位置,全文索引就存放在这个位置(这个是老版本的SQL Server,SQL Server 2008开始全文目录存在于数据库的文件组中了,已经不需要对全文目录设置位置)

当你查询全文索引列的时候,SQLSERVER就会扫描全文目录,去找你需要查询的记录,所以当你查看执行计划的时候会看到一个执行计划“远程扫描”
远程扫描基本上占了大头


全SQL建立全文搜索

在网上看到很多文章都是用SSMS来建立全文索引,本人想用全SQL的方式建立全文索引
(1)先在D盘建立一个文件夹fulltext
建立全文索引的方式有两种

USE [pratice]
GO

--创建全文索引的方式1:

-------------开启全文索引和创建全文索引目录  全文目录创建的路径是D:\fulltext
--fulltext_pratice是自己自定义的全文目录名称
EXEC [sys].[sp_fulltext_database] @action = 'enable' -- varchar(20)

--如果数据库中已存在全文目录fulltext_pratice要先drop掉
--EXEC [sys].[sp_fulltext_catalog] @ftcat = 'fulltext_pratice', -- sysname
--    @action = 'drop' -- varchar(20)
    
EXEC [sys].[sp_fulltext_catalog] @ftcat = 'fulltext_pratice2', -- sysname
    @action = 'create', -- varchar(20)
    @path = N'D:\fulltext' -- nvarchar(101),注意现在声明@path参数已经没有任何意义,该参数不会起任何作用,只是个保留参数而已。因为SQL Server 2008开始全文目录存在于数据库的文件组中了,已经不需要对全文目录设置位置

建立[dbo].[Person]表 ,注意创建全文索引的表必须要有一个唯一的非空索引,并且这个唯一的非空的索引只能是一个字段,不能是组合字段,所以[dbo].[Person]表中有主键[PK_Person],使得列[ID]是非空且唯一的

CREATE TABLE [dbo].[Person](
    [Name] [nvarchar](50) NULL,
    [ID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
    [Age] [int] NULL,
    [CreateTime] [datetime] NULL,
 CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

为表[dbo].[Person]创建全文索引, 索引列为[Name]

EXEC [sys].[sp_fulltext_table] @tabname = N'Person', -- nvarchar(517)
@action = 'create', -- varchar(50)
@ftcat = fulltext_pratice, -- sysname
@keyname = PK_Person -- sysname
--@language参数的意义在于分词,到时候会把[Name]字段里的数据按照各个国家的语言来进行分词,具体的数字您可以自己指定
--2052代表中文,1033代表美文,2057代表英文

EXEC [sys].[sp_fulltext_column] @tabname = N'Person', -- nvarchar(517)
    @colname = [Name], -- sysname
    @action = 'add', -- varchar(20)
    @language = 2052 -- int  2057 is the LCID for 英语  1033 :美语   2052:中文

至于SQLSERVER支持哪些国家的语言您可以使用下面SQL语句进行查询

SELECT * FROM  sys.fulltext_languages 

-------------激活索引
EXEC [sys].[sp_fulltext_table] @tabname = N'Person', -- nvarchar(517)
     @action = 'activate'

可以看到在全文目录的属性对话框里已经建立好全文索引

我们先向[Person]表插入8行记录

SET IDENTITY_INSERT [dbo].[Person] ON 
GO
INSERT [dbo].[Person] ([Name], [ID], [Age], [CreateTime], [rowguid]) VALUES (N'王大催', 1, 55, CAST(N'2018-11-28T22:27:48.470' AS DateTime), N'1e301a02-1ef3-e811-9185-b06ebfc5f7b4')
GO
INSERT [dbo].[Person] ([Name], [ID], [Age], [CreateTime], [rowguid]) VALUES (N'张小勇', 2, NULL, CAST(N'2018-11-28T22:27:50.370' AS DateTime), N'1f301a02-1ef3-e811-9185-b06ebfc5f7b4')
GO
INSERT [dbo].[Person] ([Name], [ID], [Age], [CreateTime], [rowguid]) VALUES (N'王大催', 3, 30, CAST(N'2018-10-25T02:03:31.060' AS DateTime), N'20301a02-1ef3-e811-9185-b06ebfc5f7b4')
GO
INSERT [dbo].[Person] ([Name], [ID], [Age], [CreateTime], [rowguid]) VALUES (N'吴学良', 4, 23, CAST(N'2018-11-28T22:26:21.937' AS DateTime), N'21301a02-1ef3-e811-9185-b06ebfc5f7b4')
GO
INSERT [dbo].[Person] ([Name], [ID], [Age], [CreateTime], [rowguid]) VALUES (N'王大催', 5, 56, CAST(N'2018-11-28T22:26:28.980' AS DateTime), N'22301a02-1ef3-e811-9185-b06ebfc5f7b4')
GO
INSERT [dbo].[Person] ([Name], [ID], [Age], [CreateTime], [rowguid]) VALUES (N'买鱼', 7, 88, CAST(N'2018-11-28T22:28:16.967' AS DateTime), N'23301a02-1ef3-e811-9185-b06ebfc5f7b4')
GO
INSERT [dbo].[Person] ([Name], [ID], [Age], [CreateTime], [rowguid]) VALUES (N'科目一', 32008, 88, CAST(N'2018-12-08T15:26:37.930' AS DateTime), N'3868ce98-bafa-e811-9185-b06ebfc5f7b4')
GO
INSERT [dbo].[Person] ([Name], [ID], [Age], [CreateTime], [rowguid]) VALUES (N'问号James', 32009, 52, CAST(N'2018-12-08T15:26:51.687' AS DateTime), N'b55a01a1-bafa-e811-9185-b06ebfc5f7b4')
GO
SET IDENTITY_INSERT [dbo].[Person] OFF
GO

然后填充全文索引,至于什么是填充全文索引这里就不详细说了,我copy的MSDN里说得很清楚

http://www.cnblogs.com/lyhabc/articles/3254782.html

填充的方式有3种:1、完全填充,2、增量填充,3、自动跟踪更改

语法:

ALTER FULLTEXT INDEX ON  表名 SET CHANGE_TRACKING OFF

一般我们首次创建完全文索引之后先完全填充索引,然后修改填充方式为自动跟踪更改,等数据有变化的时候只需要把变化的部分填充进去全文索引里

------------填充索引,首次创建完全文索引之后先完全填充索引,把数据全部放入全文索引里
USE [pratice]
GO
ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] SET CHANGE_TRACKING OFF
GO
ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] START FULL POPULATION
GO

------------修改填充方式为自动跟踪更改,等数据有变化的时候只需要把变化的部分填充进去全文索引里就可以了
USE [pratice]
GO
ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] SET CHANGE_TRACKING AUTO
GO


---------------如果是增量填充
USE [pratice]
GO
ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] SET CHANGE_TRACKING OFF
GO
--或者
ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] SET CHANGE_TRACKING MANUAL
GO
ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] START INCREMENTAL POPULATION
GO

增量填充的要求
增量填充是手动填充全文索引的一种替代机制。
您可以对 CHANGE_TRACKING 设置为 MANUAL 或 OFF 的全文索引运行增量填充。
如果全文索引的第一个填充是增量填充,它将对所有行编制索引并使其等效于完全填充。
增量填充要求索引表必须具有 timestamp 数据类型的列。 如果 timestamp 列不存在,则无法执行增量填充。
对不含 timestamp 列的表请求增量填充会导致完全填充操作。
另外,如果影响表全文索引的任意元数据自上次填充以来发生了变化,则增量填充请求将作为完全填充来执行。
这包括更改任何列、索引或全文索引定义所引起的元数据更改。
SQL Server 使用 timestamp 列标识自上次填充后发生更改的行。
然后,增量填充在全文索引中更新上次填充的当时或之后添加、删除或修改的行。
如果对表进行大量插入操作,则使用增量填充会较使用手动填充有效。
在填充结束时,全文引擎将记录新的 timestamp 值。 该值是 SQL 收集器遇到的最大 timestamp 值。
以后再启动增量填充时,将会使用此值。
若要运行增量填充,请执行使用 START INCREMENTAL POPULATION 子句的 ALTER FULLTEXT INDEX 语句

填充计划
当全文索引不是使用自动跟踪更改的时候就需要使用填充计划按照计划的时间去执行全文索引填充
填充计划分三种:

--(1)把自动跟踪更改设置为手动,然后UPDATE POPULATION更新填充
ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] SET CHANGE_TRACKING MANUAL
GO
ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] START UPDATE POPULATION;
GO

--(2)把自动跟踪更改设置为手动或者关闭,然后INCREMENTAL POPULATION增量填充
ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] SET CHANGE_TRACKING MANUAL
GO
--或者
ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] SET CHANGE_TRACKING OFF
GO
ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] START INCREMENTAL POPULATION
GO

--(3)把自动跟踪更改设置为关闭,然后进行完全填充,一般完全填充只在刚刚创建完全文索引的时候使用
ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] SET CHANGE_TRACKING OFF
GO
ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] START FULL POPULATION
GO

大家都喜欢使用SSMS的GUI界面去创建填充计划,他们以为SQLSERVER没有提供TSQL给他们创建填充计划
实际上SSMS中的填充计划界面相当于创建作业的SQL语句
下面的SQL语句是创建增量填充计划的SQL语句,大家如果想使用更新填充的话,
只需要在sp_add_jobstep作业步骤里把@command更改为
如果想更改填充计划的执行间隔,开始时间只需要执行sp_add_jobschedule来修改就可以

USE pratice ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] SET CHANGE_TRACKING MANUAL

ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] START UPDATE POPULATION;

创建增量填充计划了

--添加作业
USE [msdb]
GO
DECLARE @jobId BINARY(16)
EXEC msdb.dbo.sp_add_job @job_name = N'启动对[fulltext_test]表增量填充', @enabled = 1,
    @start_step_id = 1,
    @description = N'已为数据库pratice中的全文目录 fulltext_pratice 计划了对[fulltext_test]表的增量填充。',
    @job_id = @jobId OUTPUT
SELECT  @jobId
GO
-----------------------------------------
--指定要运行本作业的服务器
EXEC msdb.dbo.sp_add_jobserver @job_name = N'启动对[fulltext_test]表增量填充',
    @server_name = N'joe'
GO
--------------------------------------
--添加作业计划
USE [msdb]
GO
DECLARE @schedule_id INT
EXEC msdb.dbo.sp_add_jobschedule @job_name = N'启动对[fulltext_test]表增量填充',
    @name = N'fulltext_test', @enabled = 1, @freq_type = 4, @freq_interval = 1,
    @freq_subday_type = 1, @freq_subday_interval = 0,
    @freq_relative_interval = 0, @freq_recurrence_factor = 1,
    @active_start_date = 20130815, @active_end_date = 99991231,
    @active_start_time = 120742, @active_end_time = 235959,
    @schedule_id = @schedule_id OUTPUT
SELECT  @schedule_id
GO
--------------------------------------
--添加作业步骤
USE [msdb]
GO
EXEC msdb.dbo.sp_add_jobstep @job_name = N'启动对[fulltext_test]表增量填充',
    @step_name = N'全文索引', @step_id = 1, @cmdexec_success_code = 0,
    @on_success_action = 1, @on_success_step_id = -1, @on_fail_action = 2,
    @on_fail_step_id = -1, @retry_attempts = 0, @retry_interval = 0,
    @os_run_priority = 0, @subsystem = N'TSQL', @command = N'
    USE pratice
    ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] SET CHANGE_TRACKING OFF

    ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] START INCREMENTAL POPULATION

', @database_name = N'master'
GO

创建全文索引的方式2:

-------------------------------------------------------------------------
--创建全文索引的方式2: 方式2我没有找到全文目录的路径在哪里指定@path
USE [pratice]
GO

CREATE FULLTEXT INDEX ON 表名
(
    字段名                         --Full-text index column name
    TYPE COLUMN FileExtension    --Name of column that contains file type information
    Language 2052                 --2057 is the LCID for British English
)
KEY INDEX [PK_Person] ON fulltext_pratice --Unique index
WITH CHANGE_TRACKING AUTO            --Population type; 填充类型为自动跟踪更改
GO
-----------------------------------------------------

卸载全文索引

-----------------------卸载全文索引------------------
EXEC sp_fulltext_table 'fulltext_test', 'deactivate'
EXEC sp_fulltext_column 'fulltext_test', 'id', 'drop'
EXEC sp_fulltext_table 'fulltext_test', 'drop'
EXEC sp_fulltext_catalog 'fulltext_pratice', 'stop'
EXEC sp_fulltext_catalog 'fulltext_pratice', 'drop'

分词和非索引字

SQLSERVER会根据创建全文索引的时候指定的国家语言来对数据进行分词和排除非索引字
比如下面指定2052就是按照中文的意思去对数据进行分词

EXEC [sys].[sp_fulltext_column] @tabname = N'Person', -- nvarchar(517)
    @colname = [Name], -- sysname
    @action = 'add', -- varchar(20)
    @language = 2052 -- int  2057 is the LCID for 英语  1033 :美语   2052:中文

还有一个就是非索引字,在全文查询的过程当中会排除这些非索引字
MSDN中的解释:

非索引字表。提供系统非索引字表,该非索引字表包含一组基本非索引字(也称为干扰词)。
“非索引字”是对搜索没有任何帮助并且被全文查询忽略的词。 例如,在英语区域设置中,
诸如“a”、“and”、“is”和“the”之类的词都被视为非索引字。 通常情况下
,需要配置一个或多个同义词库文件和非索引字表。 有关详细信息,请参阅为全文搜索配置和管理非索引字和非索引字表。

这里非索引字表实际上就是指下面路径下的噪声文件,因为我的SQLSERVER安装在C盘
C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\FTData
默认的全文目录也会在这个路径下创建如果你创建全文目录的时候不指定全文目录的路径的话

猜你喜欢

转载自www.cnblogs.com/OpenCoder/p/10088164.html