Как этот запрос останавливается? - PullRequest
3 голосов
/ 27 января 2012

Я смотрю на этот запрос , и меня несколько смущают некоторые вещи.

-- T-SQL large update table
USE tempdb;
SELECT * INTO SOD
FROM AdventureWorks2008.Sales.SalesOrderDetail
GO
--(121317 row(s) affected)

-- SQL update in batches of 10,000
WHILE (2 > 1)
  BEGIN
    BEGIN TRANSACTION
    UPDATE TOP ( 10000 ) SOD
    SET    UnitPriceDiscount = 0.08,
           ModifiedDate = CONVERT(DATETIME,CONVERT(CHAR(10),getdate(),112))
    WHERE  ModifiedDate < CONVERT(DATETIME,CONVERT(CHAR(10),getdate(),112))

    IF @@ROWCOUNT = 0
      BEGIN
        COMMIT TRANSACTION
         BREAK
      END
    COMMIT TRANSACTION
    -- 1 second delay
    WAITFOR DELAY '00:00:01'
  END -- WHILE
GO

/* Messages

(10000 row(s) affected)

(10000 row(s) affected)

(10000 row(s) affected)

(10000 row(s) affected)

(10000 row(s) affected)

(10000 row(s) affected)

(10000 row(s) affected)

(10000 row(s) affected)

(10000 row(s) affected)

(10000 row(s) affected)

(10000 row(s) affected)

(10000 row(s) affected)

(1317 row(s) affected)

(0 row(s) affected)
*/
-- Cleanup
DROP TABLE SOD
GO

------------
  1. Он создает временную таблицу?SELECT * INTO SOD если так, то действительно ли это нужно?Могу ли я просто использовать часть while и ниже?
  2. Как IF @@ROWCOUNT = 0 может стать нулем?Делает ли это какое-то самовозрастание или что-то в этом роде?

Редактировать

Это то, что у меня есть сейчас, но я все еще думаю, что существует бесконечный цикл или что-то в этом роде

BEGIN TRAN

declare
  @rows_updated int ,
  @rowCount int,
  @batch_size   int
  set @rows_updated = -1
  set @batch_size   = 10000
  set @rowCount = 0;

Declare @xx VARCHAR(20) DECLARE @length INT
SET @length = 17 SET @xx = 'XXXXXXXXXXXXXXXX'

while ( @rows_updated != 0 )
  begin
    update top(@batch_size)  myTbl
    SET myNumber = SUBSTRING(@xx, 0, @length - len(RIGHT(myNumber, 4))) + RIGHT(myNumber, 4) 
    WHERE myDate <'2011-Jan-02' 
    set @rows_updated = @@rowcount
   set @rowCount += 10000
    print @rowCount
  end

ROLLBACK

Я сделал подсчет

select count(*) from myTbl
where  myDate < '2011-Jan-02' 

, это возвращает счет 1,448,982

последняя полученная мной распечатка была 31,110,000

Редактировать 2

Я добавил это, и теперь оно останавливается, но все равно не на 100%, где это должно быть в

while (Select Count(*) From myTbl Where myDate  <'2011-Jan-02' ) >=  @rowCount

Редактировать 3

Я думаю, что edit 2 просто делает одни и те же 10000 строк снова и снова.

Ответы [ 4 ]

2 голосов
/ 27 января 2012
  1. SOD - это новая таблица, созданная оператором SELECT ... INTO, см. здесь
  2. @@ROWCOUNT получает значение 0, когда предыдущий оператор UPDATE больше не работаетобновляет любые записи или, другими словами, когда все записи в таблице SOD уже обновлены.

РЕДАКТИРОВАТЬ фиксированный первый ответ

1 голос
/ 27 января 2012

Предоставленный скрипт выполняет следующие действия:

  • Создает / загружает постоянную таблицу SOD

  • while (true)

    • начинает транзакцию
    • обновляет не более 10000 строк таблицы SOD, где дата изменения меньше текущей даты, устанавливая скидку на единицу цены на 0,08 и устанавливая дату изменения на текущую дату.
    • фиксирует транзакцию
    • , если строки не были изменены, выходит из цикла
    • повтор

Сначалаbegin transaction и commit transaction не нужны при обычной установке SQL Server, если только вы явно не изменили параметр IMPLICIT_TRANSACTIONS, выполнив SET IMPLICIT_TRANSACTIONS ON, и в этом случае оператор BEGIN TRANSACTION не требуется.Причина в том, что по умолчанию SQL-серверы работают в режиме автоматической фиксации, поэтому каждый оператор срабатывает: sotto voce , commit при успехе или rollback при сбое.

Кроме того, логика немного неуклюжа.Я бы написал цикл следующим образом:

declare
  @rows_updated int ,
  @batch_size   int

set @rows_updated = -1
set @batch_size   = 10000

while ( @rows_updated != 0 )
  begin

    update top @batch_size SOD
    set UnitPriceDiscount = 0.08 ,
        ModifiedDate      = convert(datetime,convert(char(10),getdate(),112))
    where ModifiedDate    < convert(datetime,convert(char(10),getdate(),112))

    set @rows_updated = @@rowcount

  end

, что может сделать происходящее немного более прозрачным.

0 голосов
/ 27 января 2012

Создает копию AdventureWorks2008.Sales.SalesOrderDetail в tempdb. Затем UPDATE SOD таблица 10000 записей одновременно. Это делается, когда размер таблиц больше, так как меньшие транзакции завершаются быстрее, что приводит к меньшему количеству конфликтов для таблицы.

@@ROWCOUNT обновляется внутри после любого оператора DML, если не указано SET ROWCOUNT OFF. Поэтому в конечном итоге SOD не будет иметь никаких соответствующих записей, и ни одна не будет обновлена, что завершает цикл.

Все это кажется бессмысленным, поскольку SOD выброшено в конце. Поэтому, если в этом коде нет ничего другого, я не могу понять, почему копия создается, обновляется, а затем удаляется.

0 голосов
/ 27 января 2012

Он не создает временную таблицу, SELECT ... INTO SOD FROM ... создает точную копию (данные и схему) таблицы SalesOrderDetail. Таблица SOD не может существовать до этого оператора, в противном случае SQL Server выдаст ошибку. И в отличие от временной таблицы, SOD будет сохраняться до тех пор, пока на нем не будет запущено DROP TABLE. Временная таблица существует только на время создания идентификатора процесса (или, поскольку вы создаете таблицу в tempdb, она исчезнет при следующем перезапуске SQL Server).

@@rowcount будет нулевым, если нет строк, на которые влиял последний оператор DML. Другими словами, если обновленные строки отсутствуют, @@rowcount будет равен нулю и выйдет из бесконечного цикла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...