聚集索引和非聚集索引
SQL索引一步到位http://www.cnblogs.com/AK2012/archive/2013/01/04/2844283.html
SQL SERVER中有多種索引類型。
按存儲結構區分:“聚集索引(又稱聚類索引,簇集索引)”,“分聚集索引(非聚類索引,非簇集索引)”
按數據唯一性區分:“唯一索引”,“非唯一索引”
按鍵列個數區分:“單列索引”,“多列索引”。
SqlServer索引的原理與應用http://www.cnblogs.com/knowledgesea/p/3672099.html
那麼怎麼理解索引是從大量數據中尋找少量數據呢?下面我們舉個例子來說明。
如果一個數據表的記錄平均長度爲400字節,則100萬條記錄需要5萬個數據頁,其計算公式如下:
1000000/(8060/400)=50000
如果該數據表建立聚集索引,鍵值爲4個字節長度,而ID的數據長度爲13個字節,因此索引結構每條記錄爲20個字節。
4(聚集索引鍵值)+13(ID鍵值)+3(管理信息)=20
以ID字段所建立的索引,100%填充率,則總分頁數約爲2482頁,其計算方式如下:
1000000/(8060/20)
即使是使用80%的填充率來計算也只有3106頁。其計算方式如下:
1000000/((8060*0.8)/20)
從上面可以看出如果是第一種情況,則索引頁只佔到總數據頁的5%:
2482/50000=0.04964
即使考慮取每頁只填充80%的索引數據,第二種情況,索引頁也只是佔總數據頁的6%:
3106/50000=0.06212
再說如果查詢條件中的字段建立索引,則由於索引鍵值數據都是以B-Tree有順序的擺放,所以可採用二分查找找數據。也就是2的N次方大於記錄數,就可以找到該條數據。而2的20次方大於100萬,因此最多找尋20次就可以找到該條記錄。由於比較次數少,數據結構也小,節省訪問硬盤與內在的資源,索引將大幅提升找尋數據的效率。SQL SERVER爲提高訪問與查找對比的效率,用來作索引的數據域鍵值愈小愈好,也就是要讓分頁儘量存更多的鍵值記錄。
……
當堆或聚集表具有多個分區時,每個分區都有一個堆或 B 樹結構,其中包含該指定分區的行組。例如,如果一個聚集表有 4 個分區,那麼將有 4 個 B 樹,每個分區一個。
……
……在索引子葉層級中的每個數據頁都有一個指針指向索引分頁的前一頁與後一頁,形成雙向鏈接串行,在內部的系統數據表包含了各索引子葉層第一個分頁的地址,爲了保證數據在邏輯上是依照聚集索引的順序存放的,……
……
當非聚集索引從結構中找到符合的記錄時,雖然在子葉層該鍵值是由小到大排序,因此可能在一個分頁上就有全部符合查詢條件的鍵值,但因爲數據表中數據行的擺放是沒有按順序的(或是說沒有按照該非聚集索引的鍵值順序擺放),所以真正符合記錄的數據是散佈在文檔各處的,而SQL SERVER每次讀取數據都是以數據頁爲單位,因此,找到一條記錄所在位置後,要先將存放該條記錄的分頁讀到內存中,再從該頁讀出記錄。
因爲BOOKMARK LOOKUP是進行隨機的I/O操作,當符合查詢的記錄很多時,通過非聚集索引訪問將導致數據頁讀取非常頻繁,就算兩條記錄在同一個分頁,該分頁也會被重複讀兩次,因此或符合的記錄有N條,就需要讀取數據表內的分頁N頁,雖然大部分的讀取操作都是針對內存中的高速緩存,但記錄數過多時一樣沒有效率,還不如數據表掃描,全部掃描一遍,把符合條件數據找出來。
雖然 SQL 2005 以後的版本中已經不在提 BOOKMARK LOOKUP了(但實際上卻是換湯不換藥),我們的很多搜索都是使用如下的搜索過程:先在非聚集中找,然後再在聚集索引中找。
SQL Server 查詢性能優化——創建索引原則(一)http://www.cnblogs.com/chillsrc/archive/2012/09/19/2694313.html
需要注意的是,在一個表中只允許存在一個聚集索引。
SQL Server創建和使用索引https://www.2cto.com/database/201301/186302.html
聚集索引
……
這個是一種特別的方法,因爲在定義主鍵的時候,會自動添加索引,好在加的是聚集索引還是非聚集索引是我們人爲可以控制的。
通過sp_helpindex 可以查看錶中的索引
execute sp_helpindex @objname = 'Employee';
go
複合索引
……
可以發現它錯了,varbinary是不可以建索引的
覆蓋索引(哈哈,沒看懂)
唯一索引
篩選索引
……
總結:
BTree 索引有聚集與非聚集之分。就查看上到聚集索引性能比非聚集索引性能要好。
非聚集索引分覆蓋索引,唯一索引,複合索引(當然聚集索引也有複合的,複合二字,只是說明索引,引用了多列),一般非聚集索引就查看上到非聚集索引中覆蓋索引的性能比別的非聚集索引性能要好,它的性能和聚集索引差不多,可是它也不是’銀彈‘ 它會用更多的磁盤空間。(哈哈,還是沒看懂)
……
http://www.cnblogs.com/JiangLe/p/4007091.html
語法(嗯,太長不看)
FETCH
[ [ NEXT | PRIOR | FIRST | LAST
| ABSOLUTE { n | @nvar }
| RELATIVE { n | @nvar }
]
FROM
]
{ { [ GLOBAL ] cursor_name } | @cursor_variable_name }
[ INTO @variable_name [ ,...n ] ]
參數
NEXT
緊跟當前行返回結果行,並且當前行遞增爲返回行。如果 FETCH NEXT 爲對遊標的第一次提取操作,則返回結果集中的第一行。NEXT 爲默認的遊標提取選項。(簡單點講取遊標中下一行數據賦值給變量)
PRIOR
返回緊鄰當前行前面的結果行,並且當前行遞減爲返回行。如果 FETCH PRIOR 爲對遊標的第一次提取操作,則沒有行返回並且遊標置於第一行之前。
FIRST
返回遊標中的第一行並將其作爲當前行。
LAST
返回遊標中的最後一行並將其作爲當前行。
ABSOLUTE
{ n | @nvar}
如果 n 或 @nvar 爲正數,則返回從遊標頭開始的第 n 行,並將返回行變成新的當前行。如果 n 或 @nvar 爲負數,則返回從遊標末尾開始的第 n 行,並將返回行變成新的當前行。如果 n 或 @nvar 爲 0,則不返回行。n 必須是整數常量,並且 @nvar 的數據類型必須爲 smallint、tinyint 或 int。
RELATIVE { n | @nvar}
如果 n 或 @nvar 爲正數,則返回從當前行開始的第 n 行,並將返回行變成新的當前行。如果 n 或 @nvar 爲負數,則返回當前行之前第 n 行,並將返回行變成新的當前行。如果 n 或 @nvar 爲 0,則返回當前行。在對遊標完成第一次提取時,如果在將 n 或 @nvar 設置爲負數或 0 的情況下指定 FETCH RELATIVE,則不返回行。n 必須是整數常量,@nvar 的數據類型必須爲 smallint、tinyint 或 int。
GLOBAL
指定 cursor_name 是指全局遊標。
cursor_name
要從中進行提取的打開的遊標的名稱。如果同時具有以 cursor_name 作爲名稱的全局和局部遊標存在,則如果指定爲 GLOBAL,則 cursor_name 是指全局遊標,如果未指定 GLOBAL,則指局部遊標。
@cursor_variable_name
遊標變量名,引用要從中進行提取操作的打開的遊標。
INTO @variable_name[,...n]
允許將提取操作的列數據放到局部變量中。列表中的各個變量從左到右與遊標結果集中的相應列相關聯。各變量的數據類型必須與相應的結果集列的數據類型匹配,或是結果集列數據類型所支持的隱式轉換。變量的數目必須與遊標選擇列表中的列數一致。
備註
如果 SCROLL 選項未在 SQL-92 樣式的 DECLARE CURSOR 語句中指定,則 NEXT 是唯一受支持的 FETCH 選項。如果在 SQL-92 樣式的 DECLARE CURSOR 語句中指定了 SCROLL 選項,則支持所有 FETCH 選項。
如果使用 Transact-SQL DECLARE 遊標擴展插件,則應用下列規則:
如果指定了 FORWARD_ONLY 或 FAST_FORWARD,則 NEXT 是唯一受支持的 FETCH 選項。
如果未指定 DYNAMIC、FORWARD_ONLY 或 FAST_FORWARD 選項,並且指定了 KEYSET、STATIC 或 SCROLL 中的某一個,則支持所有 FETCH 選項。
DYNAMIC SCROLL 遊標支持除 ABSOLUTE 以外的所有 FETCH 選項。
@@FETCH_STATUS 函數報告上一個 FETCH 語句的狀態。相同的信息記錄在由 sp_describe_cursor 返回的遊標中的 fetch_status 列中。這些狀態信息應該用於在對由 FETCH 語句返回的數據進行任何操作之前,以確定這些數據的有效性。有關詳細信息,請參閱 @@FETCH_STATUS。
權限
FETCH 權限默認授予任何有效的用戶。
示例
A. 在簡單的遊標中使用 FETCH
以下示例爲 Person.Contact 表中姓氏以字母 B 開頭的行聲明瞭一個簡單的遊標,並使用 FETCH NEXT 逐個提取這些行。FETCH 語句以單行結果集形式返回在 DECLARE CURSOR 中指定的列的值。
複製代碼
USE AdventureWorks
GO
DECLARE contact_cursor CURSOR FOR
SELECT LastName FROM Person.Contact
WHERE LastName LIKE 'B%'
ORDER BY LastName
OPEN
contact_cursor
-- Perform the first fetch.
FETCH NEXT FROM contact_cursor
-- Check @@FETCH_STATUS to see if there are any more rows to fetch.
WHILE @@FETCH_STATUS = 0
BEGIN
-- This is executed as long as the previous fetch succeeds.
FETCH NEXT FROM contact_cursor
END
CLOSE contact_cursor
DEALLOCATE contact_cursor
GO
B. 使用 FETCH 將值存入變量
以下示例與上面的示例相似,但 FETCH 語句的輸出存儲於局部變量而不是直接返回到客戶端。PRINT 語句將變量組合成單一字符串並將其返回到客戶端。
複製代碼
USE AdventureWorks
GO
-- Declare the variables to store the values returned by FETCH.
DECLARE @LastName varchar(50), @FirstName varchar(50)
DECLARE contact_cursor CURSOR FOR
SELECT LastName, FirstName FROM Person.Contact
WHERE LastName LIKE 'B%'
ORDER BY LastName, FirstName
OPEN contact_cursor
-- Perform the first fetch and store the values in variables.
-- Note: The variables are in the same order as the columns
-- in the SELECT statement.
FETCH NEXT FROM contact_cursor
INTO @LastName, @FirstName
-- Check @@FETCH_STATUS to see if there are any more rows to fetch.
WHILE @@FETCH_STATUS = 0
BEGIN
-- Concatenate and display the current values in the variables.
PRINT 'Contact Name: ' + @FirstName + ' ' + @LastName
-- This is executed as long as the previous fetch succeeds.
FETCH NEXT FROM contact_cursor
INTO @LastName, @FirstName
END
CLOSE contact_cursor
DEALLOCATE contact_cursor
GO
C. 聲明 SCROLL 遊標並使用其他 FETCH 選項
以下示例創建一個 SCROLL 遊標,使其通過 LAST、PRIOR、RELATIVE 和 ABSOLUTE 選項支持全部滾動功能。
複製代碼
USE AdventureWorks
GO
-- Execute the SELECT statement alone to show the
-- full result set that is used by the cursor.
SELECT LastName, FirstName FROM Person.Contact
ORDER BY LastName, FirstName
-- Declare the cursor.
DECLARE contact_cursor SCROLL CURSOR FOR
SELECT LastName, FirstName FROM Person.Contact
ORDER BY LastName, FirstName
OPEN contact_cursor
-- Fetch the last row in the cursor.
FETCH LAST FROM contact_cursor
-- Fetch the row immediately prior to the current row in the cursor.
FETCH PRIOR FROM contact_cursor
-- Fetch the second row in the cursor.
FETCH ABSOLUTE 2 FROM contact_cursor
-- Fetch the row that is three rows after the current row.
FETCH RELATIVE 3 FROM contact_cursor
-- Fetch the row that is two rows prior to the current row.
FETCH RELATIVE -2 FROM contact_cursor
CLOSE contact_cursor
DEALLOCATE contact_cursor
GO
請參閱
參考
CLOSE (Transact-SQL)
DEALLOCATE (Transact-SQL)
DECLARE CURSOR (Transact-SQL)
OPEN (Transact-SQL)
其他資源
Transact-SQL 遊標
http://bbs.csdn.net/topics/360194933
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DYNAMIC
Static選項相當於從tempdb裏面完全緩存一個結果集。外部修改數據,並不影響到遊標本身(修改遊標結果集任意一列都不影響)。使用Static選項的話,不能執行更新遊標的 Current of 操作
PS:就是說你在執行這段代碼的時候,另外一個窗口即時插入新數據,修改數據,刪除數據也不會影響到當前遊標
Keyset 選項
Keyset 選項也是從tempdb裏面緩存一個結果集,只緩存一個主鍵。外部修改數據,不能修改主鍵,修改其它列是有效的。如果基表該行被刪除了,@@Fetch_State返回值爲-2
PS:就是說你在執行這段代碼的時候,另外一個窗口即時插入新數據沒有影響。修改非主鍵數據可以獲取到,如果數據不存在就88啦
DYNAMIC 選項
每次獲取都即時更新,新增,修改,刪除都可以支持。動態遊標不支持 ABSOLUTE 提取選項
指定啓用了性能優化的 FORWARD_ONLY、READ_ONLY 遊標。如果指定了 SCROLL 或 FOR_UPDATE,則不能也指定 FAST_FORWARD。(嗯,看不懂)