代码之家  ›  专栏  ›  技术社区  ›  GarethOwen

如何知道SQL全文索引填充何时完成?

  •  51
  • GarethOwen  · 技术社区  · 16 年前

    我们正在为ASP.NET应用程序编写单元测试,该应用程序针对测试SQL Server数据库运行。 也就是说,ClassInitialize方法使用测试数据创建一个新数据库,ClassCleanup将删除该数据库。我们通过从代码中运行.bat脚本来实现这一点。

    被测试的类被赋予一个连接到单元测试数据库而不是生产数据库的连接字符串。

    据我所知,全文索引总是在后台填充的。我希望能够:

    1. 使用同步(transact-SQL?)语句创建完全填充的全文索引,或
    2. 找出全文填充何时完成,是否有回调选项,或者是否可以重复询问?

    我目前的解决方案是在类初始化方法结束时强制延迟5秒,因为我在文档中找不到任何东西。

    5 回复  |  直到 16 年前
        1
  •  52
  •   Seph    11 年前

    您可以使用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
  •  73
  •   Tom Halladay Amy B    6 年前

    我想提供一个更容易阅读的版本@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)
    
        3
  •  11
  •   JohnB    14 年前

    这是我们根据garetohen的答案创建的存储过程。它接受以逗号分隔的表列表作为参数,并等待所有表的全文索引更新。它每隔十分之一秒进行一次检查,以防止磁盘抖动,并在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
    
        4
  •  8
  •   Hannah Vernon    8 年前

    谢谢丹尼尔,你的回答让我走上了正轨。

    实际上,我使用以下T-SQL语句询问全文索引的填充状态是否为空闲:

    SELECT OBJECTPROPERTY(object_id('v_doc_desc_de'), 'TableFulltextPopulateStatus')
    

    如果人口状态不是空闲的,我会等待几秒钟,然后再次询问,直到它空闲。在检查之间等待一小段时间是很重要的,以确保全文填充不会因为连续检查填充状态而减慢。

    MSDN documentation 声明 OBJECTPROPERTYEX 函数(在表级别)建议在 FULLTEXTCATALOGPROPERTY 属性为“PopulateStatus”的语句。它规定如下:

        5
  •  4
  •   Community Mohan Dere    9 年前

    要等待全文目录完成其所有表和视图的填充,而不必指定它们的名称,可以使用以下存储过程。这是JohnB对这个问题的回答和cezarm对a的回答的结合 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
    
        6
  •  0
  •   Sylvia    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();
    
    推荐文章