1. 程式人生 > >SQL Server全文搜尋(轉載)

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
預設的全文目錄也會在這個路徑下建立如果你建立全文目錄的時候不指定全文目錄的路徑的話