sql >> Database >  >> RDS >> Sqlserver

Update indien anders/gewijzigd

Tijdens het compileren en uitvoeren van query's neemt SQL Server niet de tijd om erachter te komen of een UPDATE-instructie daadwerkelijk waarden zal wijzigen of niet. Het voert gewoon de schrijfbewerkingen uit zoals verwacht, zelfs als het niet nodig is.

In het scenario zoals

update table1 set col1 = 'hello'

je zou kunnen denken dat SQL niets zal doen, maar het zal - het zal alle benodigde schrijfbewerkingen uitvoeren alsof je de waarde daadwerkelijk hebt gewijzigd. Dit gebeurt zowel voor de fysieke tabel (of geclusterde index) als voor alle niet-geclusterde indexen die in die kolom zijn gedefinieerd. Dit veroorzaakt schrijfacties naar de fysieke tabellen/indexen, herberekening van indexen en schrijfacties in transactielogboeken. Als u met grote datasets werkt, zijn er enorme prestatievoordelen als u alleen rijen bijwerkt die een wijziging ondergaan.

Als we de overhead van deze schrijfbewerkingen willen vermijden wanneer dat niet nodig is, moeten we een manier bedenken om te controleren of er updates nodig zijn. Een manier om te controleren of een update nodig is, is door iets toe te voegen als 'where col <> 'hallo'.

update table1 set col1 = 'hello' where col1 <> 'hello'

Maar dit zou in sommige gevallen niet goed werken, bijvoorbeeld als u meerdere kolommen in een tabel met veel rijen zou bijwerken en van slechts een kleine subset van die rijen de waarden zouden worden gewijzigd. Dit komt door de noodzaak om vervolgens op al die kolommen te filteren, en niet-gelijkheidspredikaten zijn over het algemeen niet in staat om indexzoekopdrachten te gebruiken, en de overhead van het schrijven naar tabellen en indexen en transactielogboekvermeldingen zoals hierboven vermeld.

Maar er is een veel beter alternatief met een combinatie van een EXISTS-clausule met een EXCEPT-clausule. Het idee is om de waarden in de doelrij te vergelijken met de waarden in de overeenkomende bronrij om te bepalen of een update daadwerkelijk nodig is. Bekijk de aangepaste query hieronder en bekijk het aanvullende queryfilter dat begint met EXISTS. Merk op hoe in de EXISTS-component de SELECT-instructies geen FROM-component hebben. Dat deel is vooral belangrijk omdat dit alleen maar een extra constante scan en een filterbewerking in het queryplan toevoegt (de kosten van beide zijn triviaal). Dus wat u uiteindelijk krijgt, is een zeer lichtgewicht methode om te bepalen of een UPDATE überhaupt nodig is, waardoor onnodige schrijfoverhead wordt vermeden.

update table1 set col1 = 'hello'
/* AVOID NET ZERO CHANGES */
where exists 
    (
    /* DESTINATION */
    select table1.col1
    except
    /* SOURCE */
    select col1 = 'hello'
    )

Dit ziet er te ingewikkeld uit in vergelijking met het controleren op updates in een eenvoudige WHERE-clausule voor de eenvoudige scenerio in de oorspronkelijke vraag wanneer u één waarde bijwerkt voor alle rijen in een tabel met een letterlijke waarde. Deze techniek werkt echter heel goed als u meerdere kolommen in een tabel bijwerkt en de bron van uw update een andere query is en u schrijf- en transactielogboekvermeldingen wilt minimaliseren. Het presteert ook beter dan het testen van elk veld met <>.

Een vollediger voorbeeld zou kunnen zijn

update table1
   set col1 = 'hello',
       col2 = 'hello',
       col3 = 'hello'
/* Only update rows from CustomerId 100, 101, 102 & 103 */
where table1.CustomerId IN (100, 101, 102, 103)
/* AVOID NET ZERO CHANGES */
  and exists 
    (
    /* DESTINATION */
    select table1.col1
           table1.col2
           table1.col3
    except
    /* SOURCE */
    select z.col1,
           z.col2,
           z.col3
      from #anytemptableorsubquery z
     where z.CustomerId = table1.CustomerId
    )


  1. Het niet gebruiken van transacties in Quill om een-op-veel relationele objecten INSERT

  2. Een database verwijderen in cPanel

  3. Hoe SQL Server op Linux te installeren

  4. Paginanummer paginanummer beperken