我们正在编写针对测试SQL Server数据库运行的ASP.NET应用程序的单元测试。 也就是说,ClassInitialize方法使用测试数据创建一个新数据库,ClassCleanup删除数据库。我们通过从代码运行.bat脚本来实现这一目的。
为测试中的类提供连接字符串,该字符串连接到单元测试数据库而不是生产数据库。
我们的问题是,数据库包含全文索引,需要使用测试数据完全填充,以便我们的测试按预期运行。
据我所知,全文索引总是在后台填充。我希望能够:
我目前的解决方案是在类初始化方法结束时强制延迟 - 5秒似乎有效 - 因为我在文档中找不到任何内容。
答案 0 :(得分:60)
我想提供一个更容易阅读的@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
FROM sys.fulltext_catalogs AS cat
结果:
LastPopulated PopulateStatus
----------------------- ----------------------------------
2012-05-08 14:51:37.000 Idle
(1 row(s) affected)
答案 1 :(得分:41)
您可以使用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事件探查器来监视在打开目录的属性对话框时SQL Server Management Studio发出的命令。该对话框包含人口状态的指示,所有显示的信息都是使用T-SQL查询的。
答案 2 :(得分:10)
这是我们根据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
答案 3 :(得分:8)
谢谢丹尼尔,你的回答让我走上正轨。
我实际上使用以下T-SQL语句来询问全文索引的填充状态是否为空闲:
SELECT OBJECTPROPERTY(object_id('v_doc_desc_de'), 'TableFulltextPopulateStatus')
'v_doc_desc_de'是我们索引的数据库视图的名称。
如果人口状态不是空闲的,我会等待几秒钟然后再问,直到它空闲。重要的是要在检查之间等待一小段时间,以确保通过不断检查人口状态来减缓全文填充。
MSDN documentation表示OBJECTPROPERTYEX
函数(在表级别)推荐使用属性为'PopulateStatus'的FULLTEXTCATALOGPROPERTY
语句。它陈述如下:
将在SQL Server的未来版本中删除以下属性:LogSize和PopulateStatus。避免在新的开发工作中使用这些属性,并计划修改当前使用其中任何属性的应用程序。
答案 4 :(得分:3)
要等待全文目录完成其所有表和视图的填充而不必指定其名称,可以使用以下存储过程。这是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
答案 5 :(得分:0)
我做了以下事情:
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();