2016-08-02 71 views
-1

我有一個聲明,我用來添加或更新一行數據。我在觀察SQL更新行時沒有明顯的變化。我試圖弄清楚SQL爲什麼要阻止它更新的原因。爲什麼SQL在沒有檢測到更改時更新某些行?

我以這種方式更新約1,000行(一個接一個),只有2行似乎更新時,我創建的掩碼建議他們不應該。

下面是相關的SQL代碼片段:

... 
ELSE IF NOT EXISTS (
    SELECT PERMIT_STATUS, PERMIT_LOCATION, PERMIT_COMMODITY, PERMIT_TYPE_CODE, PERMIT_TYPE_DESCRIPTION, PERMIT_ALLOCATION_METHOD, PERMIT_OPERATION_NAME, OWNERS, SHARE_PERCENTAGE, OPERATOR, MINERALS, PERMIT_DURATION_YEARS, PERMIT_DURATION_MONTHS, PERMIT_AREA, PERMIT_AREA_UNIT, PERMIT_OFFSHORE_ONSHORE, PERMIT_STATUS_DATE, PERMIT_MINERAL_GROUP, PERMIT_MP, SUBSEQUENT_TO_PERMIT, PERMIT_COMMENCEMENT_DATE, PERMIT_EXPIRY_DATE, PERMIT_GRANT_DATE, PERMIT_NONEXCLUSIVE_YN, ShapeGeoJson, Removed 
    FROM MyTable 
    WHERE PERMIT_NUMBER = @PERMIT_NUMBER 
    INTERSECT 
    SELECT @PERMIT_STATUS, @PERMIT_LOCATION, @PERMIT_COMMODITY, @PERMIT_TYPE_CODE, @PERMIT_TYPE_DESCRIPTION, @PERMIT_ALLOCATION_METHOD, @PERMIT_OPERATION_NAME, @OWNERS, @SHARE_PERCENTAGE, @OPERATOR, @MINERALS, @PERMIT_DURATION_YEARS, @PERMIT_DURATION_MONTHS, @PERMIT_AREA, @PERMIT_AREA_UNIT, @PERMIT_OFFSHORE_ONSHORE, @PERMIT_STATUS_DATE, @PERMIT_MINERAL_GROUP, @PERMIT_MP, @SUBSEQUENT_TO_PERMIT, @PERMIT_COMMENCEMENT_DATE, @PERMIT_EXPIRY_DATE, @PERMIT_GRANT_DATE, @PERMIT_NONEXCLUSIVE_YN, @ShapeGeoJson, @Removed 
) 
BEGIN 
    UPDATE MyTable 
    SET PERMIT_STATUS = @PERMIT_STATUS 
     ,PERMIT_LOCATION = @PERMIT_LOCATION 
     ,PERMIT_COMMODITY = @PERMIT_COMMODITY 
     ,PERMIT_TYPE_CODE = @PERMIT_TYPE_CODE 
     ,PERMIT_TYPE_DESCRIPTION = @PERMIT_TYPE_DESCRIPTION 
     ,PERMIT_ALLOCATION_METHOD = @PERMIT_ALLOCATION_METHOD 
     ,PERMIT_OPERATION_NAME = @PERMIT_OPERATION_NAME 
     ,OWNERS = @OWNERS 
     ,SHARE_PERCENTAGE = @SHARE_PERCENTAGE 
     ,OPERATOR = @OPERATOR 
     ,MINERALS = @MINERALS 
     ,PERMIT_DURATION_YEARS = @PERMIT_DURATION_YEARS 
     ,PERMIT_DURATION_MONTHS = @PERMIT_DURATION_MONTHS 
     ,PERMIT_AREA = @PERMIT_AREA 
     ,PERMIT_AREA_UNIT = @PERMIT_AREA_UNIT 
     ,PERMIT_OFFSHORE_ONSHORE = @PERMIT_OFFSHORE_ONSHORE 
     ,PERMIT_STATUS_DATE = @PERMIT_STATUS_DATE 
     ,PERMIT_MINERAL_GROUP = @PERMIT_MINERAL_GROUP 
     ,PERMIT_MP = @PERMIT_MP 
     ,SUBSEQUENT_TO_PERMIT = @SUBSEQUENT_TO_PERMIT 
     ,PERMIT_COMMENCEMENT_DATE = @PERMIT_COMMENCEMENT_DATE 
     ,PERMIT_EXPIRY_DATE = @PERMIT_EXPIRY_DATE 
     ,PERMIT_GRANT_DATE = @PERMIT_GRANT_DATE 
     ,PERMIT_NONEXCLUSIVE_YN = @PERMIT_NONEXCLUSIVE_YN 
     ,ShapeGeoJson = @ShapeGeoJson 
     ,UpdatedUtc = GETUTCDATE() 
     ,Removed = @Removed 
     ,UpdatedMask = (
      IIF (PERMIT_STATUS != @PERMIT_STATUS, 4096, 0) + 
      IIF (PERMIT_LOCATION != @PERMIT_LOCATION, 256, 0) + 
      IIF (PERMIT_COMMODITY != @PERMIT_COMMODITY, 512, 0) + 
      IIF (PERMIT_TYPE_CODE != @PERMIT_TYPE_CODE, 64, 0) + 
      IIF (PERMIT_TYPE_DESCRIPTION != @PERMIT_TYPE_DESCRIPTION, 128, 0) + 
      IIF (PERMIT_ALLOCATION_METHOD != @PERMIT_ALLOCATION_METHOD, 1024, 0) + 
      IIF (PERMIT_OPERATION_NAME != @PERMIT_OPERATION_NAME, 2048, 0) + 
      IIF (OWNERS != @OWNERS, 1048576, 0) + 
      IIF (SHARE_PERCENTAGE != @SHARE_PERCENTAGE, 2097152, 0) + 
      IIF (OPERATOR != @OPERATOR, 4194304, 0) + 
      IIF (MINERALS != @MINERALS, 8388608, 0) + 
      IIF (PERMIT_DURATION_YEARS != @PERMIT_DURATION_YEARS, 32768, 0) + 
      IIF (PERMIT_DURATION_MONTHS != @PERMIT_DURATION_MONTHS, 65536, 0) + 
      IIF (PERMIT_AREA != @PERMIT_AREA, 67108864, 0) + 
      IIF (PERMIT_AREA_UNIT != @PERMIT_AREA_UNIT, 134217728, 0) + 
      IIF (PERMIT_OFFSHORE_ONSHORE != @PERMIT_OFFSHORE_ONSHORE, 262144, 0) + 
      IIF (PERMIT_STATUS_DATE != @PERMIT_STATUS_DATE, 8192, 0) + 
      IIF (PERMIT_MINERAL_GROUP != @PERMIT_MINERAL_GROUP, 131072, 0) + 
      IIF (PERMIT_MP != @PERMIT_MP, 524288, 0) + 
      IIF (SUBSEQUENT_TO_PERMIT != @SUBSEQUENT_TO_PERMIT, 33554432, 0) + 
      IIF (PERMIT_COMMENCEMENT_DATE != @PERMIT_COMMENCEMENT_DATE, 16, 0) + 
      IIF (PERMIT_EXPIRY_DATE != @PERMIT_EXPIRY_DATE, 32, 0) + 
      IIF (PERMIT_GRANT_DATE != @PERMIT_GRANT_DATE, 8, 0) + 
      IIF (PERMIT_NONEXCLUSIVE_YN != @PERMIT_NONEXCLUSIVE_YN, 16384, 0) + 
      IIF (ShapeGeoJson != @ShapeGeoJson, 137438953472, 0) + 
      IIF (Removed != @Removed, 274877906944, 0) 
     ) 
    WHERE PERMIT_NUMBER = @PERMIT_NUMBER; 
END 
... 

我使用頂部的INTERSECT方法來檢測任何行的數據列的變化。這是因爲比較列中的NULL值更容易。

而且您可以看到UpdatedMask正在更新一個值,以指示哪些列已更新。發生問題時,將其設置爲0(並且按預期工作時,我會看到正確的UpdatedMask)。

我看不到任何拼寫錯誤或明顯的邏輯錯誤。所以我想知道是否可能是由於SQL Azure負載不知何故,通過大量的ShapeGeoJson列逐個更新這麼多的記錄?

這裏的表定義的情況下,它是非常有用的:

CREATE TABLE [dbo].[MyTable](
    [PERMIT_NUMBER] [varchar](30) NOT NULL, 
    [PERMIT_STATUS] [varchar](30) NULL, 
    [PERMIT_LOCATION] [varchar](4000) NULL, 
    [PERMIT_COMMODITY] [varchar](8) NULL, 
    [PERMIT_TYPE_CODE] [varchar](4000) NULL, 
    [PERMIT_TYPE_DESCRIPTION] [varchar](255) NULL, 
    [PERMIT_ALLOCATION_METHOD] [varchar](4000) NULL, 
    [PERMIT_OPERATION_NAME] [varchar](4000) NULL, 
    [OWNERS] [varchar](4000) NULL, 
    [SHARE_PERCENTAGE] [varchar](4000) NULL, 
    [OPERATOR] [varchar](220) NULL, 
    [MINERALS] [varchar](4000) NULL, 
    [PERMIT_DURATION_YEARS] [varchar](4000) NULL, 
    [PERMIT_DURATION_MONTHS] [varchar](4000) NULL, 
    [PERMIT_AREA] [varchar](4000) NULL, 
    [PERMIT_AREA_UNIT] [varchar](4) NULL, 
    [PERMIT_OFFSHORE_ONSHORE] [varchar](4000) NULL, 
    [PERMIT_STATUS_DATE] [date] NULL, 
    [PERMIT_MINERAL_GROUP] [varchar](4000) NULL, 
    [PERMIT_MP] [varchar](4000) NULL, 
    [SUBSEQUENT_TO_PERMIT] [varchar](4000) NULL, 
    [PERMIT_COMMENCEMENT_DATE] [date] NULL, 
    [PERMIT_EXPIRY_DATE] [date] NULL, 
    [PERMIT_GRANT_DATE] [date] NULL, 
    [PERMIT_NONEXCLUSIVE_YN] [char](1) NULL, 
    [ShapeGeoJson] [varchar](max) NOT NULL, 
    [CreatedUtc] [datetime] NOT NULL, 
    [UpdatedUtc] [datetime] NOT NULL, 
    [Removed] [bit] NOT NULL, 
    [UpdatedMask] [bigint] NULL, 
CONSTRAINT [PK_MyTable_1] PRIMARY KEY CLUSTERED 
(
    [PERMIT_NUMBER] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 

任何想法?

更新過程每晚都會運行,因此我會密切關注那些似乎違反規則的行,以查看是否存在某種模式。我現在已經看過幾次了,但忽略了保留之前調查的數據。

+1

看到這種類型的代碼給我的噩夢。我會建議使用ORM。 –

+0

@MarAnderson - 我正在使用Dapper,但是因爲我不想每次往返取一個巨大的ShapeGeoJson時都返回數據庫,所以只需比較一下我就可以保存SQL Azure DTU在添加/更新過程中單一電話。但是,是的,並不是最優雅的SQL。 – Gavin

+0

請閱讀[this](http://spaghettidba.com/2015/04/24/how-to-post-a-t-sql-question-on-a-public-forum/)瞭解一些關於改善問題的提示。 – HABO

回答

0

我設法深入瞭解問題。計算UpdatedMask值的邏輯在比較時沒有考慮NULL值。

所以更新是有效的。這是計算的UpdatedMask,它是無效的。

所以,現在我已經變醜我的SQL更進一步:

UpdatedMask = (
    IIF (ISNULL(PERMIT_STATUS, '') != ISNULL(@PERMIT_STATUS, ''), 4096, 0) + 
    IIF (ISNULL(PERMIT_LOCATION, '') != ISNULL(@PERMIT_LOCATION, ''), 256, 0) + 
    ... 
) 
0

在你的代碼中你有代碼重複。您有INTERSECT/EXISTS部分,您可以檢查是否更新了某些內容,然後您將代碼計算出UpdatedMask,然後重複邏輯。

我會建議先刪除重複的邏輯。那麼發現問題並將其修復到一個地方會容易得多。

下面的代碼顯示了更新記錄的另一種方法,只依靠代碼來計算UpdatedMask。

-- We will update MyTable from data in the NewData alias that contains 
-- all of the new values and UpdatedMask 
UPDATE U 
SET U.PERMIT_STATUS = NewData.PERMIT_STATUS 
    ,U.PERMIT_LOCATION = NewData.PERMIT_LOCATION 
    .... all other columns .... 
    ,U.UpdatedMask = NewData.UpdatedMask 
FROM MyTable U 
    INNER JOIN (
     SELECT T.PERMIT_STATUS = @PERMIT_STATUS 
      ,T.PERMIT_LOCATION = @PERMIT_LOCATION 
      ... all other columns ... 
      ,UpdatedMask = (
       IIF (T.PERMIT_STATUS != @PERMIT_STATUS, 4096, 0) + 
       IIF (T.PERMIT_LOCATION != @PERMIT_LOCATION, 256, 0) + 
       ... all other columns .... 
      ) 
     FROM MyTable T 
     WHERE T.PERMIT_NUMBER = @PERMIT_NUMBER 
    -- In the join clause we only take rows that are actually updated 
    ) AS NewData ON NewData.UpdatedMask<>0 
WHERE U.PERMIT_NUMBER = @PERMIT_NUMBER; 
+0

好點。 UpdatedMask是在開發過程中稍後添加的,因此被認爲是後來的想法。我喜歡這個建議,但是爲什麼有些記錄會通過當前的邏輯滑動,我仍然很感興趣。 – Gavin

+0

@Gavin,你可以通過分析特定的數據類型和數據值來找到答案。你可以提交一些嗎? –

+0

感謝您花時間看一看,非常感謝。我設法找到問題。這是因爲我在計算UpdatedMask值時沒有處理NULL值。我已經在這裏發佈了答案,但不能將其標記爲答案,直到2天過去爲止。管理恢復備份並準確觀察更新期間受影響的行正在發生的情況。 – Gavin

相關問題