Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Актуализиране, ако е различно/променено

По време на компилиране и изпълнение на заявка, SQL Server не отделя време, за да разбере дали оператор UPDATE действително ще промени някакви стойности или не. Той просто изпълнява записите според очакванията, дори и да са ненужни.

В сценарий като

update table1 set col1 = 'hello'

може да си помислите, че SQL няма да направи нищо, но ще го направи – той ще извърши всички необходими записи, сякаш всъщност сте променили стойността. Това се случва както за физическата таблица (или клъстериран индекс), така и за всички неклъстерирани индекси, дефинирани в тази колона. Това причинява записи във физическите таблици/индекси, преизчисляване на индекси и записи в регистъра на транзакциите. Когато работите с големи набори от данни, има огромни ползи за производителността от актуализирането само на редове, които ще получат промяна.

Ако искаме да избегнем режийните разходи за тези записи, когато не са необходими, трябва да измислим начин да проверяваме за необходимостта от актуализиране. Един от начините да проверите за необходимостта от актуализиране е да добавите нещо като „where col <> 'hello'.

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

Но това няма да се представи добре в някои случаи, например ако актуализирате няколко колони в таблица с много редове и стойностите на само малка част от тези редове действително ще бъдат променени. Това се дължи на необходимостта след това да се филтрират всички тези колони и предикатите за неравенство обикновено не могат да използват търсене на индекси и допълнителните разходи за запис на таблица и индекс и записи в регистъра на транзакциите, както е споменато по-горе.

Но има много по-добра алтернатива, използваща комбинация от клауза EXISTS с клауза EXCEPT. Идеята е да се сравнят стойностите в целевия ред със стойностите в съответстващия изходен ред, за да се определи дали действително е необходима актуализация. Вижте модифицираната заявка по-долу и разгледайте допълнителния филтър за заявка, започващ с EXISTS. Обърнете внимание как вътре в клаузата EXISTS изразите SELECT нямат клауза FROM. Тази част е особено важна, защото добавя само допълнително постоянно сканиране и филтърна операция в плана на заявката (цената и на двете е тривиална). Така че това, което получавате в крайна сметка, е много лек метод за определяне дали изобщо е необходима АКТУАЛИЗАЦИЯ, като се избягва ненужното натоварване на записа.

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

Това изглежда прекалено сложно в сравнение с проверката за актуализации в проста клауза WHERE за простия сценарий в оригиналния въпрос, когато актуализирате една стойност за всички редове в таблица с литерална стойност. Тази техника обаче работи много добре, ако актуализирате множество колони в таблица и източникът на вашата актуализация е друга заявка и искате да сведете до минимум записите и записите в регистрационните файлове на транзакциите. Освен това се представя по-добре от тестването на всяко поле с <>.

По-пълен пример може да бъде

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. месеца между две дати в sql сървър с начална и крайна дата на всяка от тях в sql сървър

  2. В SQL Server 2008 мога да предам параметър със стойност на таблица към моята съхранена процедура от NHibernate. Как да постигна същото в Oracle

  3. Как да получите списък на цялата база данни от sql сървър в разгъващ се списък с помощта на c#.net

  4. Работа с типа данни на SQL Server XML

  5. Как мога да избегна използването на Cursor за прилагане на този псевдо код - SQL Server