2015-05-19 38 views
1

我們有存儲在遠程服務器的表中的圖像。該表使用圖像列數據類型。將作業複製到作業中的遠程服務器會導致1024字節的無效數據長度

我們的複製客戶端(不是自定義的SQL服務器複製)使用一系列觸發器和作業從遠程位置將數據複製到中央數據庫中央數據庫。我發現,使用複製作業複製的圖像始終爲1024字節。

我寫了一個查詢來試圖找出爲什麼發生這種情況,這是我發現的。

如果我在SSMS中運行下面的查詢,會遇到問題,我可以更新和修復由原始複製作業複製的記錄的圖像數據。但是,如果我在作業中運行相同的查詢,則圖像列的大小始終爲1024個字節 - 與複製作業運行時的大小相同。

任何人都知道爲什麼會發生這種情況?

謝謝。

SET NOCOUNT ON 

IF object_id('tempdb..#tmp') IS NOT NULL 
    DROP TABLE #tmp 

DECLARE @msg VARCHAR(255) = NULL 
    ,@cnt INT = 1 

SET @msg = 'Count' + ' | ' + ' DocDate' + ' | ' + 'LocId' + ' | ' + '  TicketId' + ' | ' + 'DocSeq' + ' | ' + 'DataLen' 

RAISERROR (
     @msg 
     ,10 
     ,0 
     ) 
WITH NOWAIT 

SET @msg = '----------------------------------------------------------------' 

RAISERROR (
     @msg 
     ,10 
     ,0 
     ) 
WITH NOWAIT 

SELECT ptd.LocId 
    ,pt.DocTime 
    ,ptd.TicketId 
    ,ptd.DocSeq 
INTO #tmp 
FROM TICKET_DOCUMENT (nolock) ptd 
INNER JOIN TICKET (nolock) pt 
    ON pt.TicketId = ptd.TicketId 
     AND convert(DATE, pt.DocTime) BETWEEN '2/1/15' AND '2/14/15' 
WHERE DATALENGTH(Data) = 1024 

WHILE EXISTS (
     SELECT 1 
     FROM #tmp 
     ) 
BEGIN 
    DECLARE @server VARCHAR(20) 
     ,@LocId INT 
     ,@sql VARCHAR(4000) 

    SELECT TOP 1 @LocId = LocId 
    FROM #tmp 

    SELECT @server = servername 
    FROM Location 
    WHERE LocId = @LocId 

    DECLARE @tmp TABLE (
     TicketId BINARY (6) 
     ,DocTime DATETIME 
     ,DocSeq INT 
     ,Data IMAGE 
     ) 

    IF OBJECT_ID('tempdb..#lmt') IS NOT NULL 
     DROP TABLE #lmt 

    SELECT TOP 1 * 
    INTO #lmt 
    FROM #tmp 
    WHERE LocId = @LocId 

    SET @sql = 'SELECT rptd.TicketId 
    ,t.DocTime 
    ,rptd.DocSeq 
    ,rptd.Data 
FROM ' + @server + '.db_name.dbo.ticket_document rptd 
INNER JOIN #lmt t 
    ON t.TicketId = rptd.TicketId 
     AND t.DocSeq = rptd.DocSeq 
     AND t.LocId = rptd.LocId' 

    INSERT INTO @tmp 
    EXEC (@sql) 

    WHILE EXISTS (
      SELECT 1 
      FROM @tmp 
      ) 
    BEGIN 
     DECLARE @TicketId BINARY (6) 
      ,@DocSeq INT 
      ,@DataLen INT 
      ,@DocTime DATETIME 

     SELECT TOP 1 @TicketId = TicketId 
      ,@DocTime = DocTime 
      ,@DocSeq = DocSeq 
      ,@DataLen = datalength(Data) 
     FROM @tmp 

     BEGIN TRANSACTION 

     UPDATE TICKET_DOCUMENT 
     SET Data = t.Data 
     FROM TICKET_DOCUMENT ptd 
     INNER JOIN @tmp t 
      ON t.TicketId = ptd.TicketId 
       AND t.DocSeq = ptd.DocSeq 
     WHERE t.TicketId = @TicketId 
      AND t.DocSeq = @DocSeq 

     COMMIT TRANSACTION 

     SET @msg = dbo.udf_PadString('left', convert(VARCHAR(6), @cnt), ' ', 5) + ' | ' + convert(VARCHAR, @DocTime, 101) + ' | ' + dbo.udf_PadString('left', convert(VARCHAR(2), @LocId), ' ', 7) + ' | 0x' + convert(VARCHAR, @TicketId, 2) + ' | ' + dbo.udf_PadString('left', convert(VARCHAR(3), @DocSeq), ' ', 6) + ' | ' + dbo.udf_PadString('left', convert(VARCHAR(11), @DataLen), ' ', 7) 

     RAISERROR (
       @msg 
       ,10 
       ,0 
       ) 
     WITH NOWAIT 

     DELETE 
     FROM @tmp 
     WHERE TicketId = @TicketId 
      AND DocSeq = @DocSeq 

     SET @cnt += 1 
    END 

    DELETE #tmp 
    FROM #tmp t 
    INNER JOIN #lmt l 
     ON l.LocId = t.LocId 
      AND l.TicketId = t.TicketId 
      AND l.DocSeq = t.DocSeq 
END 
+0

可以嘗試使用臨時表#TMP2代替@tmp? – Tim3880

回答

1

由於您看到SSMS和SQL Agent之間的差異行爲,這意味着會話級別設置是原因。嘗試加入以下對該查詢的頂部:

  1. 完每個語句/查詢與分號(;)
  2. SET TEXTSIZE 2147483647; 
    

    與查詢相關的自身注Delcare #tmp並做INSERT INTO #tmp SELECT...,就像你爲@tmp

  3. 完全刪除(nolock)提示,或至少添加WITH關鍵字提示左:TableName WITH (NOLOCK)
  4. Delcare #lmtINSERT INTO #lmt SELECT/EXEC...,就像你做@tmp
  5. 更換兩個同時用明確的CURSORs變量循環(他們更高效;同時,基於集的更新甚至會爲內部的while循環更好,除非你真的想在每個項目的統計數據)
  6. @tmp
  7. 更換 UPDATE TICKET_DOCUMENTUPDATE ptd
  8. 使用VARBINARY(MAX)而不是IMAGEData場的數據類型
  9. 刪除BEGIN TRAN/COMMIT(他們沒有任何用處單個查詢)
  10. 同時沒有指定,因爲默認的大小不指定VARCHAR(或NVARCHARVARBINARY)不總是 30:它是有時1,取決於它在哪裏使用!
  11. 刪除所有致電udf_PadString的電話,因爲他們不需要。相反,使用的RAISERROR內置填充功能如下:

    1. 聲明下面的腳本的頂部:

      DECLARE @StringDocTime VARCHAR(30); 
      
    2. 變化@TicketIdVARBINARY(6),而不是BINARY (6)

    3. 用以下內容替換您當前的SET @msg = dbo.udf_PadString('left',...

      SET @StringDocTime = convert(VARCHAR(30), GETDATE(), 101); 
      
      RAISERROR('%5d | %s | %7d | %#.6x | %6d | %7d', 10, 0, 
            @cnt, @StringDocTime, @LocId, @TicketId, @DocSeq, @DataLen) 
            WITH NOWAIT; 
      
+0

這解決了它。 'SET TEXTSIZE 2147483647;'另外,感謝其他提示。我是一名C#開發人員,因爲它沒有被強制執行,所以懶惰了。我怎樣才能在服務器級別設置這個,所以我不需要在工作中做到這一點?這樣我在這裏做的事情就沒有必要,因爲正常的複製會複製圖像。 – fourwhey

+0

我應該考慮將列轉換爲varbinary(max)嗎? – fourwhey

+0

@fourwhey沒有可以找到的服務器範圍的設置,並且出於某種原因,默認大小爲4k。但是,您可以在作業步驟以及應用程序代碼中進行設置。請先致電該聲明。您可以將它設置在任何位置,以便您再也不需要此修正腳本。是的,絕對使用VARBINARY(MAX)而不是IMAGE。 TEXT/NTEXT/IMAGE數據類型自SQL Server 2005以來已棄用;-)。 –

0

這是最有可能的最大文本REPL大小選項。 您可以在服務器上運行以下代碼,並讓我知道什麼是config_value & run_value目前設置爲?

exec sp_configure 'max text repl size (B)' 
+0

name:max text repl size(B),minimum:-1,maximum:2147483647,config_value:65536,run_value:65536 – fourwhey

+0

@fourwhey'max text repl size(B)'與您的問題無關,因爲它只適用「到事務複製和更改數據捕獲「,並且您聲明您創建了自己的複製系統。有關更多信息,請參見[max text repl size Server Configuration Option](https://msdn.microsoft.com/zh-cn/library/ms179573.aspx)。 –

+0

@srutzky我儘可能多的想到了,但無論如何也發佈了它。謝謝你確認。 – fourwhey

相關問題