概述
全文引擎使用全文索引中的信息來編譯可快速搜索表中的特定詞或詞組的全文查詢。全文索引將有關重要的詞及其位置的信息存儲在數據庫表的一列或多列中。全文索引是一種特殊類型的基於標記的功能性索引,它是由 SQL Server 全文引擎生成和維護的。生成全文索引的過程不一樣於生成其餘類型的索引。全文引擎並不是基於特定行中存儲的值來構造 B 樹結構,而是基於要編制索引的文本中的各個標記來生成倒排、堆積且壓縮的索引結構。在 SQL Server 2008 中,全文索引大小僅受運行 SQL Server 實例的計算機的可用內存資源限制。javascript
最近遇到一個需求,須要在一個100萬的表中經過關鍵字對一個大型字符字段進行檢索,相似於百度搜索引擎的搜索,查詢出全部包含關鍵字的數據並進行分頁處理,而且將匹配度最高的數據排在第一位,要求查詢響應時間控制在1秒左右。html
測試環境:SQL Server 2008 r2java
目錄
全文索引概念
- 全文索引是針對數據表,只能對錶建立全文索引,不能對數據庫建立全文索引。
- 每一個數據庫能夠不包含全文目錄或包含多個全文目錄,一個全文目錄能夠包含多個全文索引,但一個全文索引只能用於構成一個全文目錄。
- 一個數據表只能建立一個全文索引,一個全文索引能夠包含多個字段。
- 建立全文索引的表必需要有一個惟一的非空索引,而且這個惟一的非空的索引只能是一個字段,不能是組合字段。
- 每一個表只容許有一個全文索引。若要對某個表建立全文索引,該表必須具備一個惟一且非 Null 的列。您能夠對如下類型的列建立全文索引:char、varchar、nchar、nvarchar、text、ntext、image、xml、varbinary 和 varbinary(max),從而可對這些列進行全文搜索。對數據類型爲 varbinary、varbinary(max)、image 或 xml 的列建立全文索引須要您指定類型列。類型列是用來存儲每行中文檔的文件擴展名(.doc、.pdf、xls 等)的表列。
全文搜索由全文引擎提供支持。全文引擎有兩個角色:索引支持和查詢支持。git
全文搜索體系結構:sql
從 SQL Server 2008 開始,全文搜索體系結構包括如下進程:數據庫
- SQL Server 進程 (sqlservr.exe)
- 篩選器後臺程序宿主進程 (fdhost.exe)。
SQL Server 進程組件:服務器
- 用戶表 這些表包含要進行全文索引的數據。
- 全文收集器 全文收集器使用全文爬網線程。它負責計劃和驅動對全文索引的填充,並負責監視全文目錄。
- 同義詞庫文件 這些文件包含搜索項的同義詞。
- 非索引字表對象 非索引字表對象包含對搜索無用的常見詞列表。
- SQL Server 查詢處理器 查詢處理器編譯並執行 SQL 查詢。若是 SQL 查詢包含全文搜索查詢,則在編譯和執行期間該查詢都會發送到全文引擎。查詢結果將與全文索引相匹配。
- 全文引擎 SQL Server 中的全文引擎現已與查詢處理器徹底集成。全文引擎編譯和執行全文查詢。做爲查詢執行的一部分,全文引擎可能會接收來自同義詞庫和非索引字表的輸入。在 SQL Server 2008 和更高版本中,SQL Server 的全文引擎在 SQL Server 查詢處理器內部運行。
- 索引編寫器(索引器) 索引編寫器生成用於存儲索引標記的結構。
- 篩選器後臺程序管理器 篩選器後臺程序管理器負責監視全文引擎篩選器後臺程序宿主的狀態。
篩選器後臺程序宿主組件:函數
篩選器後臺程序宿主是一個由全文引擎啓動的進程。它運行下列全文搜索組件,這些組件負責對錶中的數據進行訪問、篩選和斷字,同時還負責對查詢輸入進行斷字和提取詞幹:工具
篩選器後臺程序宿主的組件以下:post
- 協議處理程序 此組件從內存中取出數據,以進行進一步的處理,並訪問指定數據庫的用戶表中的數據。其職責之一是從全文索引列中收集數據,並將所收集的數據傳遞給篩選器後臺程序宿主,從而由該宿主根據須要應用篩選和斷字符。
- 篩選器 某些數據類型須要篩選,而後才能爲文檔中的數據(包括 varbinary、varbinary(max)、image 或 xml 列中的數據)建立全文索引。給定文檔採用何種篩選器取決於文檔類型。例如,Microsoft Word (.doc) 文檔、Microsoft Excel (.xls) 文檔和 XML (.xml) 文檔分別使用不一樣的篩選器。而後,篩選器從文檔中提取文本塊區,刪除嵌入的格式並保留文本,若有可能的話也會保留有關文本位置的信息。結果將以文本化信息流的形式出現。
- 斷字符和詞幹分析器 斷字符是特定於語言的組件,它根據給定語言的詞彙規則查找詞邊界(「斷字」)。每一個斷字符都與用於組合動詞及執行變形擴展的特定於語言的詞幹分析器組件相關聯。在建立索引時,篩選器後臺程序宿主使用斷字符和詞幹分析器來對給定表列中的文本數據執行語言分析。與全文索引中的表列相關的語言將決定爲列建立索引時要使用的斷字符和詞幹分析器。
建立全文索引
啓動服務
在SQL Server配置管理工具中,找到'SQL Full-text Filter Daemon Launcher'服務用本地用戶啓動。
建立全文目錄
打開須要建立全文目錄的數據庫-存儲-全文目錄-右鍵新建全文目錄
用語句建立全文目錄
CREATE FULLTEXT CATALOG [FD_HouseSearch]WITH ACCENT_SENSITIVITY = ON
AS DEFAULT
AUTHORIZATION [dbo]
此外還能夠經過存儲過程建立全文目錄,而且能夠指定全文目錄文件所在磁盤上的位置,以下所示:
–建立全文索引的方式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_pratice’, – sysname
@action = ‘create’, – varchar(20)
@path = N’D:\fulltext’ – nvarchar(101)
固然使用SSMS建立全文目錄的時候也會有一個選項叫你選擇目錄位置,全文索引就存放在這個位置
從SQL Server 2008 開始全文目錄已經存儲在數據庫文件組中,因此再也不須要像上面截圖同樣單獨指定全文目錄的位置了,這極大的方便了數據庫的備份和還原。在SQL Server 2016中,經過SMSS建立全文目錄時,已經沒有位置選項了,以下所示:
建立全文索引
右鍵須要建立全文索引的表-全文索引-定義全文索引
1.全文索引必需要有一個惟一非空索引,這裏選擇主鍵。
2.選擇須要全文搜索的列,而且選擇斷字符語言,由於該字段主要用來存儲中文,因此這裏也選擇了簡體中文。
斷字符:斷字符用來對全文搜索數據進行語言分析,查找單詞的邊界,也就是怎樣將一段很長的內容拆分紅平常的詞語或字。例如「全文搜索」,可能會斷字成「全文」、‘搜索’、‘全’、‘文’、‘搜’、‘索’等符合中國人正常的習慣的詞或字。
3.選擇跟蹤方式,這裏選擇自動跟蹤,就是表發生更改時自動填充索引。
4.選擇全文目錄、索引文件、非索引字表
非索引字表:在剛纔的斷字中講了怎樣斷字,這裏就是將斷的字保存在一張表中,該處選擇系統默認的非索引字表.
----查詢斷字表
SELECT TOP 1000 * FROM sys.dm_fts_index_keywords(db_id(''), object_id(''))
5.填充計劃
能夠新建填充計劃來填充全文索引,填充計劃能夠是徹底填充、增量填充、更新填充。
這裏說明下填充計劃這個東西,若是使用語句建立填充計劃,其實你會發現所謂的填充計劃就是一個SqlAgent裏面的Job,而後執行了更新全文索引的Sql語句,以下所示用語句建立增量填充計劃:
--添加做業
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
此外全文索引的填充計劃有三種分別是
更新填充:
--(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
增量填充(須要注意的是:增量填充要求數據表必須具備 timestamp 數據類型的列。 若是 timestamp 列不存在,則沒法執行增量填充。另外,若是影響表全文索引的任意元數據自上次填充以來發生了變化,則增量填充請求將做爲徹底填充來執行。 這包括更改任何列、索引或全文索引定義所引發的元數據更改):
--(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
關於Sql Server中的timestamp數據類型列的介紹,能夠參考下面這段摘要:
timestamp
timestamp 這種數據類型表現自動生成的二進制數,確保這些數在數據庫中是惟一的。timestamp 通常用做給錶行加版本戳的機制。存儲大小爲 8 字節。
註釋
Transact-SQL timestamp 數據類型與在 SQL-92 標準中定義的 timestamp 數據類型不一樣。SQL-92 timestamp 數據類型等價於 Transact-SQL datetime 數據類型。
Microsoft® SQL Server™ 未來的版本可能會修改 Transact-SQL timestamp 數據類型的行爲,使它與在標準中定義的行爲一致。到那時,當前的 timestamp 數據類型將用 rowversion 數據類型替換。
Microsoft® SQL Server™ 2000 引入了 timestamp 數據類型的 rowversion 同義詞。在 DDL 語句中儘量使用 rowversion 而不使用 timestamp。rowversion 受數據類型同義詞行爲的制約。有關更多信息,請參見數據類型同義詞。
在 CREATE TABLE 或 ALTER TABLE 語句中,沒必要爲 timestamp 數據類型提供列名:
CREATE TABLE ExampleTable (PriKey int PRIMARY KEY, timestamp)
若是沒有提供列名,SQL Server 將生成 timestamp 的列名。rowversion 數據類型同義詞不具備這樣的行爲。指定 rowversion 時必須提供列名。
一個表只能有一個 timestamp 列。每次插入或更新包含 timestamp 列的行時,timestamp 列中的值均會更新。這一屬性使 timestamp 列不適合做爲鍵使用,尤爲是不能做爲主鍵使用。對行的任何更新都會更改 timestamp 值,從而更改鍵值。若是該列屬於主鍵,那麼舊的鍵值將無效,進而引用該舊值的外鍵也將再也不有效。若是該表在動態遊標中引用,則全部更新均會更改遊標中行的位置。若是該列屬於索引鍵,則對數據行的全部更新還將致使索引更新。
不可爲空的 timestamp 列在語義上等價於 binary(8) 列。可爲空的 timestamp 列在語義上等價於 varbinary(8) 列。
徹底填充:
--(3)把自動跟蹤更改設置爲關閉,而後進行徹底填充,通常徹底填充只在剛剛建立徹底文索引的時候使用
ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] SET CHANGE_TRACKING OFF
GO
ALTER FULLTEXT INDEX ON [dbo].[fulltext_test] START FULL POPULATION GO
這三種填充類型的詳細解釋,請見以下MSDN連接:
https://msdn.microsoft.com/zh-cn/library/ms142575.aspx
用語句建立全文索引
--語句少了不少默認參數,其它就按系統默認便可
CREATE FULLTEXT INDEX ON dbo.Housetest (Description ) KEY INDEX PK_Housetest ON FD_HouseSearch
全文謂詞
全文查詢使用全文謂詞(CONTAINS 和 FREETEXT)以及全文函數(CONTAINSTABLE 和 FREETEXTTABLE)。它們支持複雜的 Transact-SQL 語法,這種語法支持各類形式的查詢詞。若要編寫全文查詢,必須瞭解什麼時候以及如何使用這些謂詞和函數。
CONTAINS 謂詞能夠搜索:
- 詞或短語。
- 詞或短語的前綴。
- 與另外一個詞相鄰的詞。
- 由另外一個詞的詞形變化而生成的詞(例如,drive 一詞是 drives、drove、driving 和 driven 詞形變化的詞幹)。
- 使用同義詞庫肯定的另外一個詞的同義詞(例如,metal 一詞可能有 aluminum 和 steel 等同義詞)。
---下面的示例將查找包含 "Mountain"
USE AdventureWorks2008R2; GO
SELECT Name, ListPrice FROM Production.Product WHERE CONTAINS(Name, 'Mountain'); GO
–下面的示例將查找包含 "Mountain"或 「Road」
USE AdventureWorks2008R2;
GO
SELECT Name
FROM Production.Product
WHERE CONTAINS(Name, ’ 「Mountain」 OR 「Road」 ')
GO
–-下面的示例返回的全部產品名稱中,其 Name 列中至少有一個詞之前輟 chain 開頭
USE AdventureWorks2008R2;
GO
SELECT Name
FROM Production.Product
WHERE CONTAINS(Name, ’ 「Chain*」 ');
GO
FREETEXT謂詞的用法這裏就不作解釋了!
MSDN上的全文索引謂詞介紹
CONTAINS (Transact-SQL)
FREETEXT (Transact-SQL)
需求
如今來講一下我最近的需求,表數據100萬條,數據這裏就不弄出來了,只把方案說一下,title相似於文章的標題,Description是內容也是全文索引字段
方案1:like,測試後果斷排除, like關鍵字根本就不會用到全文索引,因此like作模糊查詢的效率很是差。
方案2:直接使用全文搜索進行,排序消耗大。
方案3:因爲查詢須要對Title進行排序,建Title字段的倒序索引包含其它字段,最後選擇該方案(建立Title字段的倒序索引很重要)。
--給出部分字段
CREATE TABLE [dbo].[Housetest]( [ID] [int] IDENTITY(1,1) NOT NULL, [Title] [varchar](200) NULL, [Description] [nvarchar](max) NOT NULL, [IsOnline] [tinyint] NOT NULL, CONSTRAINT [PK_Housetest] 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]
建立索引
CREATE INDEX IX_Housetest ON Housetest (Title DESC ) INCLUDE (ID, Description, IsOnline )
查詢Description包含「美園」,而且若是Title是「美園」則排在第一位,而且以分頁的形式顯示,每頁20條記錄。
select * from (SELECT ROW_NUMBER() OVER(Order by (case when Title='美園' Then 1 Else 0 End) desc ) as RowsNumber,ID,Title,Description From Housetest Where contains(Description,'美園') and IsOnline=1) tab1 where RowsNumber between 1 and 20
總結
你們不要拿這個與搜索引擎作對比,確定是無法比的,由於我這裏只須要解決需求就好,因此方案適合我目前的需求。
全文索引功能相似於百度的搜索引擎,可是百度這類搜索引擎有本身的數據字典,在關鍵字表中對關鍵字進行排序,保存關鍵字對應的 文檔id,一個文檔只會保留不多的關鍵字,就跟平時寫文章要添加標籤同樣,通常一篇文章就幾個標籤,當搜索的時候匹配的速度就會很是快,這就須要一個很完善的數據字典表。
全文搜索還有另外的一個功能就是FileStream,須要添加文件流,在服務中啓用該功能能夠在字段中將文檔以二進制的形式保存在字段當中,這樣大型文檔也能夠隨數據庫一塊兒備份,不少網站存儲圖片都是存儲圖片的路徑,這樣備份數據庫的時候圖片不會一塊兒備份。
全文索引帶來好處的同時也會對性能有必定的影響,特別是在進行篩選操做的時候對服務器性能會帶來影響,因此選擇一個功能的同時須要考慮對性能帶來的影響。
這裏有個題外話,全文搜索也會用到操做系統的搜索服務,詳情點擊這裏
全文索引不方便的地方:備份,還原,附加數據庫很是不方便,須要特別指定全文目錄的文件夾,是否須要附加全文目錄,以前項目經理就是這個緣由而放棄使用
全文搜索,他以前搞的一個網站的評論功能就須要使用全文搜索,聽他說自從那次使用全文搜索以後如今都沒有使用了,如今他使用like關鍵字來代替全文
可是,由於全文有分詞,數據壓縮,搜索條件比較靈活等功能因此我的以爲like關鍵字是沒有辦法和全文搜索比較的
原文連接
</div>
<div class="postDesc">posted @ <span id="post-date">2017-06-02 20:34</span> <a href="https://www.cnblogs.com/OpenCoder/">PowerCoder</a> 閱讀(<span id="post_view_count">892</span>) 評論(<span id="post_comment_count">0</span>) <a href="https://i.cnblogs.com/EditPosts.aspx?postid=6935049" rel="nofollow">編輯</a> <a href="#" onclick="AddToWz(6935049);return false;">收藏</a></div>
</div>
<script type="text/javascript">var allowComments=true,cb_blogId=56368,cb_entryId=6935049,cb_blogApp=currentBlogApp,cb_blogUserGuid='dc8c8375-b742-de11-9510-001cf0cd104b',cb_entryCreatedDate='2017/6/2 20:34:00';loadViewCount(cb_entryId);var cb_postType=1;var isMarkdown=false;</script>
轉載來源:https://www.cnblogs.com/OpenCoder/p/6935049.html