2012-01-24 2 views
2

Не обнаружено проблем с блокировкой таблицы.Медленный UPDATE на SQL Server, даже если обновления не обновляются

У меня есть инструкция по обновлению, аналогичная этому.

UPDATE table1 
SET table1.col1 = table2.col2 
FROM table1,table2 
WHERE table1.id = table2.id 

Это берет навсегда, даже в случае Whee нет записей для обновления

работает запрос

SELECT * 
FROM table1,table2 
WHERE table1.id = table2.id 

мгновенно.

РЕШЕНИЕ НАЙДЕНО: для этого я включил «Включить фактический план выполнения», как было предложено, и рекомендовал 3 индекса, которые у меня не были, и теперь выполняет всю хранимую процедуру, которая составляет 190 операторов SQL, работающих на таблицах с 16 миллионами строк менее чем за 1 минуту. Грейсиас тому, кто это предложил.

+3

Это не повлияет на производительность, но синтаксис 'JOIN' является наихудшим. Рассмотрим 'FROM table1 JOIN table2 ON table1.id = table2.id' вместо этого. Он сохраняет логику 'JOIN' отдельно от логики' WHERE'. – Yuck

+1

В SSMS попробуйте параметр «включить фактический план выполнения», чтобы проверить, что делает SQL-сервер. – Blorgbeard

+0

Мне нравятся соединения implict для INNER Joins, логически имеет смысл для меня, и в моих исследованиях говорится, что планы выполнения идентичны для разных синтаксисов. Эта проблема подтверждается в тоннах баз данных, работающих на одном и том же программном обеспечении, даже в однопользовательском режиме. Вероятно, я хотел бы отметить, что таблица1 и таблица2 содержат около 16 миллионов записей. –

ответ

3

Вы можете использовать собственное присоединиться:

Update t 
SET t.Col1 = t2.col2 
FROM table1 t INNER JOIN 
table2 t2 ON t.PK = t2.FK 

После этого проверьте все дополнительные процессы, запущенные на этом сервере.

Используйте SQL Profiler, чтобы увидеть, что происходит за кулисами. Посмотрите, есть ли какие-либо необычные процессы/задания, которые могут повлиять на обновление. не

Это берет навсегда, даже в случае Whee нет записей в обновления

Это также, как упомянуто обновление всего до тех пор, как Соединить существует, не существует, когда условие остановки его от не обновление. Каждая отдельная строка в таблице обновляется, значение, которое col1 имеет из таблицы t, перезаписывается значением col2 из t2.

также раздел комментариев:

@Bart - и вы понимаете, что вы обновляете 16 миллионов кортежей, то право? В вашем запросе ничего не говорится о том, что значение col1 равно , переписанное col2, даже если col1 и col2 содержат одинаковое значение. Вы должны сделать что-то к эффекту WHERE col2 <> col1, так что вы только обновления значений, которые отличаются

+2

+1 - Вероятно, это будет какая-то блокировка. Я предполагаю, что 'UPDATE' хочет блокировки, даже если он не изменяет данные. – JNK

+0

99% времени, когда оператор OP и ваш будут иметь одинаковые планы выполнения. Тем не менее ... Я с вами в синтаксисе 'JOIN'. – Yuck

+0

@Yuck - утверждение не о производительности, о том, чтобы быть более выразительным, говорится в заявлении ANSI join. – JonH

6

На самом деле, вы обновляете каждую строку каждый раз. Вам нужно добавить следующую строку в ваш ИНЕКЕ:

AND table1.col1 <> table2.col2 

Вы можете добавить ISNULL упаковщиков в каждую сторону, если это обнуляемое поле.

Что происходит быстрее: чтение книги или запись над каждым словом в книге того же самого точного слова? Просто потому, что вы пишете одно и то же значение по сравнению с исходным значением, это не меняет того факта, что вы пишете значения.

Теперь, если у вас есть предложение where, которое отфильтровывало записи, имеющие соответствующие значения, и у вас все еще была очень низкая производительность, тогда у потенциального виновника было бы слишком много индексов. Я предполагаю, что это не ваша проблема здесь ...

+0

+1 потому что col1 обновляется (перезаписывается у вас) по col2 для каждой строки независимо от чего-либо. – JonH

+0

ehh, не ускорял что-либо, большую часть времени не будет никакой ситуации WHERE table1.id = table2.id, но если есть, то мне нужно, чтобы столбцы, реагирующие на коррозию, были равны. Но идея хорошая и останется в коде. –

+0

Я не понимаю, почему он обновляет каждую строку каждый раз, есть предложение WHERE, поэтому оно будет обновлять строки, имеющие идентификаторы в таблице1 и таблице2. Это может быть нуль или миллионы строк. – Lamak

2
Update t 
SET t.Col1 = t2.col2 
FROM table1 t 
INNER JOIN table2 t2 ON t.PK = t2.FK 
where t.Col1 <> t2.col2 

Это то, что вы должны бежать. SQL Server не заботится о том, чтобы значения соответствовали ему, так или иначе, обновляя их.

И я с @JonH, эти соединения implict являются antipattern sql и были заменены чем-то лучшим 20 лет назад, нет никакого оправдания, чтобы все еще писать запросы таким образом. Вы получаете случайные кросс-соединения, и их сложнее поддерживать. Additonaly, в SQL Server подразумеваемые левые и правые соединения были устаревшими, и они никогда не работали корректно. Поэтому, если вам нужно перейти на левое соединение в обслуживании, вам придется изменить весь запрос, потому что объединение implict и явных соединений может привести к неправильным ответам.

+0

+1 это правильный запрос, чтобы не обновлять все. – JonH

+0

+1 - op должен определенно использовать правильный синтаксис 'JOIN'. Но я до сих пор не понимаю, почему люди говорят, что исходное 'UPDATE' будет обновлять каждую строку каждый раз. Если в таблице 1 есть только один идентификатор, который имеет совпадение в таблице2, то будет обновляться только одна строка, я думаю, что op говорит, что – Lamak

+0

@Lamak, что происходит, когда 'col1 == col2'? Эта процедура обновления по-прежнему блокирует запись для выполнения обновления, даже если вы ничего не обновляете, значения одинаковы, поэтому зачем беспокоиться. – JonH

Смежные вопросы