2014-10-06 67 views
3

請參閱下面的代碼:TSQL不會造成死循環

declare @crimeurn varchar(20) 
DECLARE @finalresults TABLE (crime_urn varchar(20)) 
DECLARE @potentialresults TABLE (crime_urn varchar(20)) 

insert into @finalresults values ('1')  

DECLARE finalresults_cursor CURSOR FOR 
SELECT crime_urn FROM @finalresults 
OPEN finalresults_cursor 
FETCH NEXT FROM finalresults_cursor INTO @crimeurn 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    print @crimeurn 

    INSERT INTO @finalresults 
    values ('2') 

    FETCH NEXT FROM finalresults_cursor INTO @crimeurn 
END 

select * from @finalresults --line 16 

CLOSE finalresults_cursor 
DEALLOCATE finalresults_cursor 

線16顯示在SQL工作室經理5137個或12342行(它隨機變化)。我預計TSQL會導致無限循環,因爲在每次迭代遊標時,都會在表變量中插入一個插入。

爲什麼它不會導致無限循環?即爲什麼有5,137行或12,342行返回。

+0

以使其更清晰,行爲,你應該改變插入光標與@ crimeurn + 1,而不是「2」,並刪除@potentialresults,爲什麼在世界上你會使用它,不使用 – Fredou 2014-10-06 14:29:15

+0

一個光標在第一個地方插入數據? – 2014-10-06 15:42:15

+0

@肖恩蘭格,業務問題是這樣的:犯罪與犯罪b的鏈接,犯罪與鏈接到犯罪x的犯罪c有關。我不知道每條鏈中有多少鏈接。因此遊標插入是我能看到的唯一方法。 – w0051977 2014-10-06 16:19:11

回答

0

編輯:下面的信息是錯誤的,但我已經離開了它,因爲這就是我相信這是假設工作。

默認情況下,遊標不會在INSENSITIVESTATIC模式下運行。默認情況下,遊標是DYNAMICOPTIMISTIC。遊標上的documentation沒有提及動態遊標相對於INSERTS的行爲。 INSERT行爲似乎是無證的。

您可以使用SCROLL_LOCKS選項修復此問題,該選項可確保訂單保存。


因爲當你運行

DECLARE finalresults_cursor CURSOR FOR 
SELECT crime_urn FROM @finalresults 

這點後的靜態遊標的定義是固定的。更新表變量@finalresults不會更改光標finalresults_cursor

是這樣的:

X = 10 
Y = X 
X = 20 
PRINT X, Y 

輸出這樣的:

20  10 
+0

當然,這意味着將返回一行,而不是:5137或12,342。我非常肯定,當您循環訪問時,@finalresults_cursor的大小會增加。 – w0051977 2014-10-06 13:51:21

+0

@ w0051977'@ finalresults_cursor'不存在。你有一個名爲'finalresults_cursor'的遊標和一個名爲'@ finalresults'的表變量。你的循環修改'@ finalresults'。 'finalresults_cursor'保持靜態。它不是動態更新的。 – 2014-10-06 13:55:26

+0

謝謝。爲什麼返回5,137或12,342行呢? – w0051977 2014-10-06 13:56:01

0

但是,如果你不關心或不知道光標的類型,你可以使用@@CURSOR_ROWS你的循環裏面做一些「光標」邏輯:)。 Here是一些關於@@CURSOR_ROWS變量可能具有的值的文檔,具體取決於遊標的類型:。

3

您正在插入堆中。

堆是無序的。沒有特別的保證,該行將被插入到當前行之後,並在下一次獲取時被獲取。

我對你的測試框架做了一個小修改,並添加了一個IDENTITY列。就我而言,它在終止之前到達592,353行。

從下面的結果可以看出,最後一行碰巧插入到文件的較早頁面(從1623跳到184),所以從倒數第二行開始的分配有序掃描不會找到它。

enter image description here

代碼來重現。

declare @crimeurn varchar(20) 
DECLARE @finalresults TABLE (crime_urn varchar(20), ID int identity) 
DECLARE @potentialresults TABLE (crime_urn varchar(20)) 

insert into @finalresults values ('1')  

DECLARE finalresults_cursor CURSOR FOR 
SELECT crime_urn FROM @finalresults 
OPEN finalresults_cursor 
FETCH NEXT FROM finalresults_cursor INTO @crimeurn 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    print @crimeurn 

    INSERT INTO @finalresults 
    --OUTPUT INSERTED.ID 
    values ('2') 

    FETCH NEXT FROM finalresults_cursor INTO @crimeurn 
END 

select *, sys.fn_PhysLocFormatter(%%physloc%%) from @finalresults --line 16 
ORDER BY ID 

CLOSE finalresults_cursor 
DEALLOCATE finalresults_cursor 
+0

你能說清楚你的意思嗎?我知道堆棧和.net堆之間的區別。 – w0051977 2014-10-06 22:19:29

+2

a [沒有聚簇索引的表](http://msdn.microsoft.com/zh-cn/library/hh213609.aspx)。儘管即使你有一個CI,也要清楚,你需要它不允許重複,並且在鍵列上有'ORDER BY'來獲得確定性的結果。例如,將表定義更改爲'DECLARE @finalresults TABLE(crime_urn varchar(20),ID int identity primary key)',並且選擇到'SELECT crime_urn FROM @finalresults order by ID'應該無限期地運行。 – 2014-10-06 22:24:04

+0

A [與註釋鏈接](http://blogs.msdn.com/b/sqlserverstorageengine/archive/2006/09/19/761437.aspx)關於如何不保證堆插入vs讀取的順序。 – crokusek 2014-10-08 20:28:17