sql >> Database teknologi >  >> RDS >> Sqlserver

Opdater hvis anderledes/ændret

Under kompilering og udførelse af forespørgsler tager SQL Server sig ikke tid til at finde ud af, om en UPDATE-sætning faktisk vil ændre nogen værdier eller ej. Den udfører bare skrivningerne som forventet, selvom det er unødvendigt.

I scenariet som

update table1 set col1 = 'hello'

du tror måske, at SQL ikke vil gøre noget, men det vil den - det vil udføre alle de nødvendige skrivninger, som om du faktisk havde ændret værdien. Dette sker for både den fysiske tabel (eller klyngede indeks) såvel som alle ikke-klyngede indekser, der er defineret i den kolonne. Dette forårsager skrivninger til de fysiske tabeller/indekser, genberegning af indekser og transaktionslogskrivninger. Når du arbejder med store datasæt, er der enorme ydeevnefordele ved kun at opdatere rækker, der vil modtage en ændring.

Hvis vi ønsker at undgå overhead af disse skrivninger, når det ikke er nødvendigt, er vi nødt til at udtænke en måde at kontrollere behovet for at blive opdateret. En måde at kontrollere behovet for at opdatere på ville være at tilføje noget som "hvor col <> 'hello'.

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

Men dette ville ikke fungere godt i nogle tilfælde, for eksempel hvis du opdaterede flere kolonner i en tabel med mange rækker, og kun en lille delmængde af disse rækker ville faktisk få deres værdier ændret. Dette er på grund af behovet for derefter at filtrere på alle disse kolonner, og prædikater uden lighed er generelt ikke i stand til at bruge indekssøgninger, og overhead af tabel- og indeksskrivninger og transaktionslogposter som nævnt ovenfor.

Men der er et meget bedre alternativ ved at bruge en kombination af en EXISTS-klausul med en EXCEPT-klausul. Ideen er at sammenligne værdierne i destinationsrækken med værdierne i den matchende kilderække for at afgøre, om en opdatering faktisk er nødvendig. Se på den ændrede forespørgsel nedenfor, og undersøg det ekstra forespørgselsfilter, der starter med EXISTS. Bemærk, hvordan inde i EXISTS-sætningen SELECT-sætningerne ikke har nogen FROM-sætning. Denne del er særlig vigtig, fordi dette kun tilføjer en ekstra konstant scanning og en filteroperation i forespørgselsplanen (omkostningerne for begge er trivielle). Så det, du ender med, er en meget let metode til at afgøre, om en OPDATERING overhovedet er nødvendig i første omgang, så du undgår unødvendige skriveoverhead.

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

Dette ser alt for kompliceret ud i forhold til at tjekke for opdateringer i en simpel WHERE-sætning for den simple scenerio i det originale spørgsmål, når du opdaterer en værdi for alle rækker i en tabel med en bogstavelig værdi. Denne teknik fungerer dog meget godt, hvis du opdaterer flere kolonner i en tabel, og kilden til din opdatering er en anden forespørgsel, og du vil minimere skrivninger og transaktionslogposter. Det yder også bedre end at teste hvert felt med <>.

Et mere komplet eksempel kunne være

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. Opgradering af Slony-I 2.0.x til seneste version 2.1.x

  2. hvordan udlæser jeg rækkenavnet baseret på en linkende tabel?

  3. Eksporterer du Google App Engine Datastore til MySQL?

  4. Duplikatindtastning for nøgle 'PRIMARY' .Ignorerer mellemrummene for strenge