web-dev-qa-db-fra.com

Comment savoir quand la population d'index de texte intégral SQL est terminée?

Nous écrivons des tests unitaires pour notre application ASP.NET qui s'exécutent sur une base de données de test SQL Server. En d'autres termes, la méthode ClassInitialize crée une nouvelle base de données avec des données de test et ClassCleanup supprime la base de données. Nous le faisons en exécutant des scripts .bat à partir du code.

Les classes testées reçoivent une chaîne de connexion qui se connecte à la base de données de test unitaire plutôt qu'à une base de données de production.

Notre problème est que la base de données contient un index de texte intégral, qui doit être entièrement rempli avec les données de test pour que nos tests s'exécutent comme prévu.

Pour autant que je sache, l'index de texte intégral est toujours rempli en arrière-plan. J'aimerais pouvoir soit:

  1. Créez l'index de texte intégral, entièrement rempli, avec une instruction synchrone (transact-SQL?), Ou
  2. Découvrez quand la population de texte intégral est terminée, existe-t-il une option de rappel ou puis-je demander à plusieurs reprises?

Ma solution actuelle est de forcer un délai à la fin de la méthode d'initialisation de la classe - 5 secondes semble fonctionner - car je ne trouve rien dans la documentation.

54
GarethOwen

Vous pouvez interroger l'état à l'aide de FULLTEXTCATALOGPROPERTY (voir ici: http://technet.Microsoft.com/en-us/library/ms190370.aspx ).

Par exemple:

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

Vous pouvez également utiliser SQL Profiler pour surveiller les commandes que SQL Server Management Studio émet lorsque vous ouvrez la boîte de dialogue des propriétés du catalogue. La boîte de dialogue comprend une indication de l'état de la population et toutes les informations affichées sont interrogées à l'aide de T-SQL.

43
Daniel Renshaw

J'aimerais offrir une version plus facile à lire de la réponse de @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

Résultats:

LastPopulated           PopulateStatus
----------------------- ----------------------------------
2012-05-08 14:51:37.000 Idle

(1 row(s) affected)
61
Tom Halladay

Il s'agit d'une procédure stockée que nous avons créée sur la base de la réponse de GarethOwen. Il accepte une liste de tables séparées par des virgules en tant que paramètres et attend que les index de texte intégral sur chacun d'eux soient mis à jour. Il effectue cette vérification tous les dixièmes de seconde pour éviter de casser le disque et expire après 10 secondes au cas où les choses tournent lentement/cassent. Utile si vos recherches FT se font sur plusieurs index.

Appelé de la manière suivante:

EXECUTE [dbo].[WaitForFullTextIndexing] 'MY_TABLE,ALTERNATE_NAMES,TAG_GROUP_VALUES,TAG_GROUPS,FIELD_OPTION';

La source:

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 est une fonction de valeur de table que tout le monde doit avoir maintenant qui fractionne une chaîne sur un séparateur en une table temporaire:

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
10
JohnB

Merci Daniel, votre réponse m'a mis sur la bonne voie.

J'utilise en fait l'instruction T-SQL suivante pour demander si l'état de la population de l'index de texte intégral est inactif:

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

'v_doc_desc_de' est le nom de la vue de base de données que nous indexons.

Si l'état de la population n'est pas inactif, j'attends quelques secondes et demande à nouveau, jusqu'à ce qu'il soit inactif. Il est important d'attendre un peu de temps entre les vérifications pour vous assurer que la population de texte intégral n'est pas ralentie en vérifiant en continu l'état de la population.

documentation MSDN indique que la fonction OBJECTPROPERTYEX (au niveau de la table) est recommandée par rapport à l'instruction FULLTEXTCATALOGPROPERTY avec la propriété 'PopulateStatus'. Il déclare ce qui suit:

Les propriétés suivantes seront supprimées dans une future version de SQL Server: LogSize et PopulateStatus. Évitez d'utiliser ces propriétés dans de nouveaux travaux de développement et prévoyez de modifier les applications qui utilisent actuellement l'une d'entre elles.

8
GarethOwen

Pour attendre qu'un catalogue de texte intégral termine le remplissage de toutes ses tables et vues sans avoir à spécifier leurs noms, vous pouvez utiliser la procédure stockée suivante. Ceci est une combinaison de la réponse de JohnB à cette question et de la réponse par cezarm à une question connexe :

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
4
Henno Vermeulen