programing

SQL 전체 텍스트 색인 작성이 완료되었는지 어떻게 알 수 있습니까?

oldcodes 2023. 6. 23. 22:25
반응형

SQL 전체 텍스트 색인 작성이 완료되었는지 어떻게 알 수 있습니까?

테스트 SQL 서버 데이터베이스에 대해 실행되는 ASP.NET 응용 프로그램에 대한 단위 테스트를 작성하고 있습니다.즉, 클래스Initialize 메서드는 테스트 데이터가 있는 새 데이터베이스를 만들고 클래스 정리는 데이터베이스를 삭제합니다.코드에서 .bat 스크립트를 실행하여 이 작업을 수행합니다.

테스트 중인 클래스에는 프로덕션 데이터베이스가 아닌 장치 테스트 데이터베이스에 연결하는 연결 문자열이 제공됩니다.

문제는 데이터베이스에 전체 텍스트 색인이 포함되어 있다는 것입니다. 이 색인은 테스트가 예상대로 실행되려면 테스트 데이터로 완전히 채워져야 합니다.

내가 아는 한, 전체 텍스트 색인은 항상 백그라운드에 채워집니다.다음 중 하나를 수행할 수 있습니다.

  1. 동기식(트랜잭션-SQL?) 문을 사용하여 전체 텍스트 색인을 만듭니다.
  2. 전체 텍스트 입력이 언제 완료되었는지, 콜백 옵션이 있는지 또는 반복적으로 요청할 수 있는지 확인하십시오.

현재 제 해결책은 문서에서 아무것도 찾을 수 없기 때문에 수업 초기화 방법을 마지막에 강제로 지연시키는 것입니다. - 5초는 효과가 있을 것 같습니다.

저는 @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)

전체 텍스트 카탈로그 속성을 사용하여 상태를 쿼리할 수 있습니다(여기 참조: 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 Server Management Studio에서 실행하는 명령을 모니터링하기 위해 SQL Profiler를 사용할 수도 있습니다.이 대화 상자에는 모집단 상태 표시가 포함되며 표시된 모든 정보는 T-SQL을 사용하여 쿼리됩니다.

이것은 개러스 오웬의 답변을 바탕으로 우리가 만든 저장 프로시저입니다.쉼표로 구분된 테이블 목록을 매개 변수로 사용하고 모든 테이블의 전체 텍스트 색인이 업데이트될 때까지 기다립니다.디스크 스레싱을 방지하기 위해 10초마다 이 검사를 수행하며, 작업이 느리게 실행되거나 중단될 경우를 대비하여 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.debo는 구분 기호의 문자열을 임시 테이블로 분할하는 테이블 값 함수입니다.

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

고마워요 다니엘, 당신의 대답이 저를 올바른 방향으로 이끌었어요.

실제로 다음 T-SQL 문을 사용하여 전체 텍스트 색인의 채우기 상태가 유휴 상태인지 묻습니다.

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

'v_doc_doc_device_de'는 인덱싱하는 데이터베이스 보기의 이름입니다.

모집단 상태가 유휴 상태가 아니면 몇 초 기다렸다가 유휴 상태가 될 때까지 다시 묻습니다.지속적으로 모집단 상태를 확인하여 전체 텍스트 모집단의 속도가 느려지지 않도록 검사 사이에 약간의 시간을 기다리는 것이 중요합니다.

MSDN 문서에는 다음과 같이 기술되어 있습니다.OBJECTPROPERTYEX(테이블 레벨에서) 기능이 권장됩니다.FULLTEXTCATALOGPROPERTY속성이 '채우기 상태'인 문입니다.다음과 같은 내용을 담고 있습니다.

SQL Server의 향후 릴리스에서는 LogSize 및 PupplyStatus 속성이 제거될 예정입니다.새 개발 작업에서 이러한 속성을 사용하지 말고 현재 속성 중 하나를 사용하는 응용 프로그램을 수정할 계획입니다.

이름을 지정하지 않고 전체 텍스트 카탈로그가 모든 테이블 및 보기의 채우기를 완료할 때까지 기다리려면 다음 저장 프로시저를 사용할 수 있습니다.다음은 이 질문에 대한 JohnB의 답변과 관련 질문에 대한 Cezarm의 답변을 결합한 것입니다.

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

다음을 수행했습니다.

        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 서버를 사용하는 경우에도 동일한 문제가 있었습니다.데이터베이스가 성공적으로 시드되었지만 테스트를 실행했을 때 인덱스 채우기 상태가 아직 완료되지 않아 테스트에 결과가 반환되지 않았습니다.

테스트를 실행하기 전에 인덱스가 재구성되었는지 확인하기 위해 테이블에 재구성 중인 인덱스가 있는지 확인하는 쿼리가 있는 스핀락을 사용했습니다.

public MyApplication SeedDatabase( Action<MyDbContext> seed )
{
    using var scope = Services.CreateScope();
    var scopedServices = scope.ServiceProvider;
    var db = scopedServices.GetRequiredService<MyDbContext>();

    db.Database.EnsureDeleted();
    db.Database.EnsureCreated();

    CreateFullTextCatalog();
    CreateFullTextIndexes();

    seed.Invoke( db );
    db.SaveChanges();

    SpinWait.SpinUntil( () => IsFullTextPopulateStatusIdle(), TimeSpan.FromSeconds( 5 ) );

    return this;

    bool IsFullTextPopulateStatusIdle() => db.Database.SqlQuery<int>( $"select case when EXISTS(SELECT OBJECTPROPERTY(object_id, 'TableFulltextPopulateStatus') from sys.tables where OBJECTPROPERTY(object_id, 'TableFulltextPopulateStatus') <> 0) then 1  else 0  end as value" ).Single() == 0;

    void CreateFullTextCatalog() => db.Database.ExecuteSqlRaw( File.ReadAllText( Path.Combine( Directory.GetCurrentDirectory(), "Sql", "FT_Catalog.sql" ) ) );

    void CreateFullTextIndexes() => db.Database.ExecuteSqlRaw( File.ReadAllText( Path.Combine( Directory.GetCurrentDirectory(), "Sql", "FullTextIndexes.sql" ) ) );
}

언급URL : https://stackoverflow.com/questions/2727911/how-can-i-know-when-sql-full-text-index-population-is-finished

반응형