2016-08-02 44 views
-1

Ich habe eine Anweisung, die ich verwende, um eine Datenzeile hinzuzufügen oder zu aktualisieren. Ich beobachte das SQL, das eine Reihe aktualisiert, wenn keine offensichtlichen Änderungen vorhanden sind. Ich versuche herauszufinden, warum es darauf ankommt, die Zeile zu aktualisieren, wenn das SQL es verhindern sollte.Warum aktualisiert SQL einige Zeilen, wenn keine Änderungen festgestellt werden?

Ich aktualisiere etwa 1.000 Zeilen auf diese Weise (eine nach der anderen) und nur 2 Zeilen scheinen zu aktualisieren, wenn die Maske, die ich erstellt habe schlägt vor, dass sie nicht sollten.

Hier ist der entsprechende SQL-Schnipsel:

... 
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 
... 

Ich verwende die INTERSECT Methode an der Spitze eine Änderung in einen der Spalten von Zeilendaten zu erfassen. Dies liegt daran, dass es einfacher ist, NULL-Werte in Spalten zu vergleichen.

Und Sie können sehen, dass die UpdatedMask mit einem Wert aktualisiert wird, um anzuzeigen, welche Spalten aktualisiert wurden. Wenn das Problem auftritt, wird dies auf 0 festgelegt (und wenn ich wie erwartet arbeite, sehe ich eine korrekte AktualisierteMaske).

Ich kann keine Tippfehler oder offensichtliche Logikfehler sehen. Also frage ich mich, ob SQL Azure irgendwie dazu führen könnte, dass so viele Datensätze nacheinander mit einer großen ShapeGeoJson-Spalte aktualisiert werden?

Hier ist die Tabellendefinition, falls es sinnvoll ist:

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] 

Irgendwelche Ideen?

Der Update-Prozess läuft jeden Abend, also behalte ich die Zeilen im Auge, die meine Regeln zu durchbrechen scheinen, um zu sehen, ob da ein Muster ist. Ich habe das schon ein paar Mal gesehen, aber ich habe es versäumt, die Daten für frühere Untersuchungen zu bewahren.

+1

diese Art von Code sehen gibt mir Albträume. Ich würde vorschlagen, ein ORM zu verwenden. –

+0

@MrAnderson - Ich benutze Dapper, aber weil ich nicht jedes Mal einen riesigen ShapeGeoJson zurückholen möchte, um einfach zu vergleichen, dachte ich mir, ich könnte SQL Azure DTU speichern den Hinzufügen/Aktualisieren Prozess in einem Einzelruf. Aber ja, nicht das eleganteste SQL als Ergebnis. – Gavin

+0

Bitte lesen [this] (http://spaghettiba.com/2015/04/24/how-to-post-a-t-sql-question-on-a-public-forum/) für einige Tipps zur Verbesserung Ihrer Frage. – HABO

Antwort

0

Ich gelang es, das Problem zu untersuchen. Die Logik zum Berechnen des Werts "UpdatedMask" berücksichtigt NULL-Werte beim Vergleich nicht.

So ist das Update gültig. Es ist die berechnete UpdatedMask, die ungültig ist.

So jetzt meine SQL uglified noch weiter ich habe:

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

In Ihrem Code haben Sie Code-Duplizierung. Sie haben den INTERSECT/EXISTS-Teil, in dem Sie prüfen, ob etwas aktualisiert wurde oder nicht, und dann haben Sie den Code, der UpdatedMask berechnet, wo die Logik wiederholt wird.

Ich würde vorschlagen, zuerst die Duplizierung der Logik zu entfernen. Dann wird es viel einfacher sein, das Problem zu finden und es an einer Stelle zu beheben.

Der folgende Code zeigt Ihnen eine alternative Möglichkeit zur Aktualisierung der Datensätze und basiert nur auf dem Code zur Berechnung von 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

Guter Punkt. UpdatedMask wurde später im Entwicklungsprozess hinzugefügt und wurde als Nachdenken angeheftet. Ich mag den Vorschlag, bin aber immer noch ziemlich fasziniert, warum einige Aufzeichnungen die aktuelle Logik durchbrechen. – Gavin

+0

@Gavin, die Sie herausfinden können, indem Sie bestimmte Datentypen und Datenwerte analysieren. Können Sie etwas einreichen? –

+0

Danke, dass Sie sich die Zeit genommen haben, einen Blick zu werfen, sehr geschätzt. Ich habe es geschafft, das Problem zu finden. Es war, weil ich NULL-Werte nicht behandelte, wenn ich meinen UpdatedMask-Wert berechnete. Ich habe hier eine Antwort gepostet, kann sie aber nicht als Antwort markieren, bis leider 2 Tage vergangen sind. Wird verwaltet, um eine Sicherung wiederherzustellen und genau zu beobachten, was mit den betroffenen Zeilen während des Updates passiert ist. – Gavin