我如何知道 SQL 全文索引填充何时完成?
Posted
技术标签:
【中文标题】我如何知道 SQL 全文索引填充何时完成?【英文标题】:How can I know when SQL Full Text Index Population is finished? 【发布时间】:2010-04-28 08:40:18 【问题描述】:我们正在为针对测试 SQL Server 数据库运行的 ASP.NET 应用程序编写单元测试。 即 ClassInitialize 方法用测试数据创建一个新的数据库,ClassCleanup 删除该数据库。我们通过从代码运行 .bat 脚本来做到这一点。
被测类被赋予一个连接到单元测试数据库而不是生产数据库的连接字符串。
我们的问题是,数据库包含一个全文索引,需要用测试数据完全填充该索引才能使我们的测试按预期运行。
据我所知,全文索引总是在后台填充。我希望能够:
-
使用同步(transact-SQL?)语句创建完全填充的全文索引,或者
找出全文填充完成的时间,是否有回调选项,或者我可以反复询问?
我目前的解决方案是在类初始化方法结束时强制延迟 - 5 秒似乎有效 - 因为我在文档中找不到任何内容。
【问题讨论】:
【参考方案1】:我想提供一个更易于阅读的@Daniel Renshaw 答案版本:
DECLARE @CatalogName VARCHAR(MAX)
SET @CatalogName = 'FTS_Demo_Catalog'
SELECT
DATEADD(ss, FULLTEXTCATALOGPROPERTY(@CatalogName,'PopulateCompletionAge'), '1/1/1990') AS LastPopulated
,(SELECT CASE FULLTEXTCATALOGPROPERTY(@CatalogName,'PopulateStatus')
WHEN 0 THEN 'Idle'
WHEN 1 THEN 'Full Population In Progress'
WHEN 2 THEN 'Paused'
WHEN 3 THEN 'Throttled'
WHEN 4 THEN 'Recovering'
WHEN 5 THEN 'Shutdown'
WHEN 6 THEN 'Incremental Population In Progress'
WHEN 7 THEN 'Building Index'
WHEN 8 THEN 'Disk Full. Paused'
WHEN 9 THEN 'Change Tracking' END) AS PopulateStatus
结果:
LastPopulated PopulateStatus
----------------------- ----------------------------------
2012-05-08 14:51:37.000 Idle
(1 row(s) affected)
【讨论】:
将此与 Daniel Renshaw 的答案结合起来,可以很好地查询多个目录。 这两个查询都非常好,如果您不需要知道我想要的细节,这个很好。接受的答案增加了这个答案。 当您不使用任何内容时,为什么要查询 sys.fulltext_catalogs 表?您不妨从查询中删除最后一行。或者删除您的 @CatalogName 变量并在您的 SELECT 语句中使用 [name] 。 @dybzon 你确实是对的!我已将其从代码中删除【参考方案2】:您可以使用 FULLTEXTCATALOGPROPERTY 查询状态(请参阅此处:http://technet.microsoft.com/en-us/library/ms190370.aspx)。
例如:
SELECT
FULLTEXTCATALOGPROPERTY(cat.name,'ItemCount') AS [ItemCount],
FULLTEXTCATALOGPROPERTY(cat.name,'MergeStatus') AS [MergeStatus],
FULLTEXTCATALOGPROPERTY(cat.name,'PopulateCompletionAge') AS [PopulateCompletionAge],
FULLTEXTCATALOGPROPERTY(cat.name,'PopulateStatus') AS [PopulateStatus],
FULLTEXTCATALOGPROPERTY(cat.name,'ImportStatus') AS [ImportStatus]
FROM sys.fulltext_catalogs AS cat
当您打开目录的属性对话框时,您可能还想使用 SQL Profiler 来监控 SQL Server Management Studio 发出的命令。该对话框包括人口状况指示,显示的所有信息均使用 T-SQL 查询。
【讨论】:
我遇到了一个页面,指出“PopulateStatus”属性在 SQL Server 的未来版本中已/将被弃用,但我无法找到检查人口的替代方法地位。你有什么想法?见第一注:technet.microsoft.com/en-us/library/ms190370.aspx @Oskar 根据弃用功能的详细列表,technet.microsoft.com/en-us/library/cc646010.aspx,没有替代品! Joe Stefanelli 在另一个问题中发表了一条评论,提出了一个可能的替代方案:***.com/questions/3680453/… 但这一切看起来都很混乱。也许在 SQL Server 2012 中会有一个新的 FTE 系统视图,其中包含此信息... 实际上technet.microsoft.com/en-us/library/ms190370.aspx 声明我们应该在桌子上使用 OBJECTPROPERTYEX。在性能方面会更好,提供更多细节并保持支持。 technet.microsoft.com/en-us/library/ms188390.aspx 以下存在等价于提到的属性:TableFulltextPopulateStatus、TableFulltextItemCount、TableFulltextCatalogId、TableFullTextMergeStatus,还有更多(查看链接)【参考方案3】:这是我们根据 GarethOwen 的回答创建的存储过程。它接受一个逗号分隔的表列表作为参数,并等待所有这些表的全文索引都已更新。它每十分之一秒进行一次检查,以防止磁盘抖动并在 10 秒后超时,以防万一事情运行缓慢/损坏。如果您的 FT 搜索跨越多个索引,则很有用。
调用方式如下:
EXECUTE [dbo].[WaitForFullTextIndexing] 'MY_TABLE,ALTERNATE_NAMES,TAG_GROUP_VALUES,TAG_GROUPS,FIELD_OPTION';
来源:
CREATE PROCEDURE WaitForFullTextIndexing
@TablesStr varchar(max)
AS
BEGIN
DECLARE @Tables AS TABLE( [word] [varchar](8000) NULL)
INSERT INTO @Tables (word) SELECT items from dbo.Split(@TablesStr, ',');
DECLARE @NumberOfTables int;
SELECT @NumberOfTables = COUNT(*) from @Tables;
DECLARE @readyCount int;
SET @readyCount = 0;
DECLARE @waitLoops int;
SET @waitLoops = 0;
DECLARE @result bit;
WHILE @readyCount <> @NumberOfTables AND @waitLoops < 100
BEGIN
select @readyCount = COUNT(*)
from @Tables tabs
where OBJECTPROPERTY(object_id(tabs.word), 'TableFulltextPopulateStatus') = 0;
IF @readyCount <> @NumberOfTables
BEGIN
-- prevent thrashing
WAITFOR DELAY '00:00:00.1';
END
set @waitLoops = @waitLoops + 1;
END
END
GO
dbo.split 是现在每个人都必须拥有的表值函数,它将分隔符上的字符串拆分为临时表:
CREATE FUNCTION [dbo].[Split](@String varchar(8000), @Delimiter char(1))
returns @temptable TABLE (items varchar(8000))
as
begin
declare @idx int
declare @slice varchar(8000)
select @idx = 1
if len(@String)<1 or @String is null return
while @idx!= 0
begin
set @idx = charindex(@Delimiter,@String)
if @idx!=0
set @slice = left(@String,@idx - 1)
else
set @slice = @String
if(len(@slice)>0)
insert into @temptable(Items) values(@slice)
set @String = right(@String,len(@String) - @idx)
if len(@String) = 0 break
end
return
end
GO
【讨论】:
@Valamas:如果你不这样做,你仍然会阻塞你的线程。在这种情况下, Thread.Sleep 可能会更好。但这与这里的问题/答案无关。【参考方案4】:谢谢丹尼尔,你的回答让我走上了正轨。
我其实是用下面的T-SQL语句来询问全文索引的填充状态是否为Idle:
SELECT OBJECTPROPERTY(object_id('v_doc_desc_de'), 'TableFulltextPopulateStatus')
'v_doc_desc_de' 是我们索引的数据库视图的名称。
如果人口状态不是空闲的,我会等待几秒钟,然后再次询问,直到它是空闲的。请务必在检查之间等待一小段时间,以确保通过不断检查填充状态不会减慢全文填充速度。
MSDN documentation 声明建议使用 OBJECTPROPERTYEX
函数(在表级别)而不是带有属性“PopulateStatus”的 FULLTEXTCATALOGPROPERTY
语句。它声明如下:
以下属性将在 SQL Server 的未来版本中删除:LogSize 和 PopulateStatus。避免在新的开发工作中使用这些属性,并计划修改当前使用其中任何一个的应用程序。
【讨论】:
引用 Gareth 的 MSDN 声明 msdn.microsoft.com/en-us/library/ms190370(v=sql.90).aspx :“在表级别检查相应的 PopulateStatus 属性通常是更好的选择,即 OBJECTPROPERTYEX 系统函数中的 TableFullTextPopulateStatus。这个和其他新的全文属性在 OBJECTPROPERTYEX 中提供有关全文索引表的更详细信息”【参考方案5】:要等待全文目录完成其所有表和视图的填充而无需指定它们的名称,您可以使用以下存储过程。这是 JohnB 对此问题的回答和 cezarm 对related question 的回答的组合:
CREATE PROCEDURE WaitForFullTextIndexing
@CatalogName VARCHAR(MAX)
AS
BEGIN
DECLARE @status int;
SET @status = 1;
DECLARE @waitLoops int;
SET @waitLoops = 0;
WHILE @status > 0 AND @waitLoops < 100
BEGIN
SELECT @status = FULLTEXTCATALOGPROPERTY(@CatalogName,'PopulateStatus')
FROM sys.fulltext_catalogs AS cat;
IF @status > 0
BEGIN
-- prevent thrashing
WAITFOR DELAY '00:00:00.1';
END
SET @waitLoops = @waitLoops + 1;
END
END
【讨论】:
从FULLTEXTCATALOGPROPERTY中选择状态值的时候,为什么要放FROM sys.fulltext_catalogs
。这只会让它返回相同的值,不管你的数据库中有多少次全文索引,对吧?
看起来你是对的@BVernon。当使用 FULLTEXTCATALOGPROPERTY
***.com/questions/1091812/… 时,这个类似的 SO 线程答案不会从 sys.fulltext_catalogs
中选择。感谢您的精彩过程,Henno!【参考方案6】:
我做了以下事情:
var indexIsPopulating = true;
var stopWatch = new Stopwatch();
stopWatch.Start();
while (indexIsPopulating)
System.Threading.Thread.Sleep(500);
using var con = new SqlConnection(databaseConnectionString);
// using dapper here - but you just need to run query on databsae
var status = await con.QueryFirstAsync<int>("SELECT OBJECTPROPERTY(OBJECT_ID('dbo.MyTableName'), 'TableFulltextPopulateStatus'); ");
if (status == 0)
indexIsPopulating = false;
else if (stopWatch.ElapsedMilliseconds > 60000) // 1 minute
stopWatch.Stop();
throw new Exception("Full Text Index failed to populate within 1 minute.");
stopWatch.Stop();
【讨论】:
以上是关于我如何知道 SQL 全文索引填充何时完成?的主要内容,如果未能解决你的问题,请参考以下文章