1. 程式人生 > >節選翻譯《Pro SQL Server Internals, 2nd edition》(P36-P45)

節選翻譯《Pro SQL Server Internals, 2nd edition》(P36-P45)

本文選自《Pro SQL Server Internals》

作者: Dmitri Korotkevitch

原文連結:http://www.doc88.com/p-4042504089228.html

CHAPTER 2 ■ TABLES AND INDEXES: INTERNAL STRUCTURE AND ACCESS METHODS

第2章■表與索引:內部結構和訪問方法

Figure 2-4. Forwarding pointers and I/O: Reading data when forwarding pointers exist   

圖形2-4。轉發指標和I/O:在轉發指標時讀取資料

   

 As you can see, the large number of forwarding pointers leads to extra I/O operations and significantly reduces the performance of the queries accessing the data. Companion materials for this book include the script that demonstrates this problem in a large scope with a table that includes a large amount of data.  When the size of the forwarded row is reduced by another update and the data page with forwarding pointer has enough space to accommodate the updated version of the row, SQL Server may move it back to its original data page and remove the forwarding pointer row. Nevertheless, the only reliable way to get rid of all of the forwarding pointers is by rebuilding the heap table. You can do that by using an  ALTER TABLE REBUILD  statement.  Heap tables can be useful in staging environments, where you want to import a large amount of data into the system as fast as possible. Inserting data into heap tables can often be faster than inserting it into tables with clustered indexes. Nevertheless, during a regular workload, tables with clustered indexes usually outperform heap tables, which have suboptimal space control and extra I/O operations introduced by forwarding pointers.   

正如你所看到的,大量的轉發指標會導致額外的I/O操作,並顯著地降低訪問資料的查詢的效能。本書的附帶材料包括指令碼,該指令碼通過一個包含大量資料的表在大範圍內演示這個問題。當通過另一次更新減小了轉發行的大小並且具有轉發指標的資料頁有足夠的空間來容納行的更新版本時,SQL Server可以將其移動回其原始資料頁並刪除轉發指標行。然而,消除所有轉發指標的唯一可靠方法是重新構建堆表。可以通過使用ALTER表重建語句來實現這一點。堆表在希望儘快將大量資料匯入系統的暫存環境中非常有用。將資料插入堆表通常比將其插入具有叢集索引的表更快。然而,在常規工作負載期間,具有叢集索引的表通常優於具有次優空間控制和由轉發指標引入的額外I/O操作的堆表。

 

 

 Clustered Indexes

 聚集索引

 

A clustered index dictates  the physical order of the data in a table, which is sorted according to the clustered index key. The table can have only one clustered index defined.  Let’s assume that you want to create a clustered index on the heap table with the data. As a first step, which is shown in Figure  2-5 , SQL Server creates another copy of the data that is then sorted based on the value of the clustered key. The data pages are linked in a double-linked list where every page contains pointers to the next and previous pages in the chain. This list is called the  leaf level  of the index, and it contains the actual table data.  

 

聚集索引指示表中資料的物理順序,該表根據聚集索引鍵進行排序。該表只能定義一個聚集索引。假設您想要在具有資料的堆表上建立叢集索引。作為第一步,如圖2-5所示,SQL Server建立資料的另一個副本,然後根據叢集金鑰的值對其進行排序。資料頁連結在雙鏈接列表中,其中每個頁都包含指向鏈中的下一頁和前一頁的指標。這個列表稱為索引的葉子級別,它包含實際的表資料。

 

 

 

 

 

CHAPTER 2 ■ TABLES AND INDEXES: INTERNAL STRUCTURE AND ACCESS METHODS

第2章表和索引:內部結構和訪問方法

 

 

Figure 2-5. Clustered index structure:  Leaf level         

圖2-5。聚集索引結構:葉級

 

Note  The sort order on the page is controlled by a slot array. Actual data on the page is unsorted.  

註釋  頁上的排序順序由時隙陣列控制。頁面上的實際資料未排序。

 

When the leaf level consists of multiple pages, SQL Server starts to build an  intermediate level  of the index, as shown in Figure  2-6 .  

當葉級包含多個頁面時,SQL Server開始構建索引的中間級別,如圖2-6所示。

 

 Figure 2-6. Clustered index structure: Intermediate and leaf levels   

 圖2-6。聚集索引結構:中間和葉級

   

The intermediate level stores one row per leaf-level page. It stores two pieces of information: the physical address and the minimum value of the index key from the page it references. The only exception is the very first row on the first page, where SQL Server stores NULL rather than the minimum index key value. With such optimization, SQL Server does not need to update non-leaf-level rows when you insert the row with the lowest key value in the table. The pages on the intermediate levels are also linked to the double-linked list. SQL Server adds more and more intermediate levels until there is a level that includes just the single page. This level is called the  root level , and it becomes the entry point to the index, as shown in Figure 2-7 .  

中間級儲存每個葉級頁的一行。它儲存兩段資訊:實體地址和它所引用的頁面中的索引鍵的最小值。唯一的例外是第一頁的第一行,其中SQL Server儲存NULL而不是最小索引鍵值。通過這種優化,當在表中插入鍵值最低的行時,SQL Server不需要更新非葉級行。中間層次的頁面也連結到雙鏈表。SQL Server添加了越來越多的中間級別,直到有一個僅包含單個頁面的級別。這個級別稱為根級別,並且它成為索引的入口點,如圖2-7所示。

 

 

 

CHAPTER 2 ■ TABLES AND INDEXES: INTERNAL STRUCTURE AND ACCESS METHODS

第2章 ■ 表和索引:內部結構和訪問方法

 

 

Figure 2-7.  Clustered index structure:  Root level         

圖2-7。聚集索引結構:根級

 

As you can see, the index always has one leaf level, one root level, and zero or more intermediate levels. The only exception is when the index data fits into a single page. In that case, SQL Server does not create the separate root-level page, and the index consists of just the single leaf-level page. The number of levels in the index largely depends on the row and index key sizes. For example, the index on the 4-byte integer column will require 13 bytes per row on the intermediate and root levels. Those 13 bytes consist of a 2-byte slot-array entry, a 4-byte index-key value, a 6-byte page pointer, and a 1-byte row overhead, which is adequate because the index key does not contain variable-length and NULL columns. As a result, you can accommodate 8,060 bytes / 13 bytes per row = 620 rows per page. This means that, with the one intermediate level, you can store information about up to 620 * 620 = 384,400 leaf-level pages. If your data row size is 200 bytes, you can store 40 rows per leaf-level page and up to 15,376,000 rows in the index with just three levels. Adding another intermediate level to the index would essentially cover all possible integer values.

如您所見,索引總是具有一個葉子級別、一個根級別和零個或多箇中間級別。唯一的例外是當索引資料適合單個頁面時。在這種情況下,SQL Server不建立單獨的根級頁面,並且索引僅由單個葉級頁面組成。索引中的級別數量很大程度上取決於行和索引鍵的大小。例如,4位元組整數列上的索引在中間層和根層上每行需要13個位元組。這13個位元組由一個2位元組的時隙陣列條目、一個4位元組的索引鍵值、一個6位元組的頁指標和一個1位元組的行開銷組成,這足夠了,因為索引鍵不包含可變長度和NULL列。因此,您可以容納每行8060位元組/13位元組=每頁620行。這意味著,使用一箇中間級別,可以儲存最多620*620=384400個葉級頁面的資訊。如果資料行大小是200位元組,那麼可以在索引中儲存每頁40行,最多15376000行,只有三個級別。向索引中新增另一箇中間級別將基本上覆蓋所有可能的整數值。

 

Note  In real life, index fragmentation would reduce those numbers. We will talk about index fragmentation in Chapter 6 .

注意  在實際生活中,索引碎片會減少這些數字。我們將在第6章中討論索引碎片。

 

There are three different ways in which SQL Server can read data from the index. The first one is by an  ordered scan.  Let’s assume that we want to run the  SELECT Name FROM dbo.Customers ORDER BY CustomerId query. The data on the leaf level of the index is already sorted based on the  CustomerId column value. As a result, SQL Server can scan the leaf level of the index from the first to the last page and return the rows in the order in which they were stored. SQL Server starts with the root page of the index and reads the first row from there. That row references the intermediate page with the minimum key value from the table. SQL Server reads that page and repeats the process until it finds the first page on the leaf level. Then, SQL Server starts to read rows one by one, moving through the linked list of the pages until all rows have been read. Figure 2-8 illustrates this process.  

SQL Server可以以三種不同的方式從索引讀取資料。第一個是通過有序掃描。假設我們要執行SELECTNamefromdbo.Customers ORDER BY CustomerId查詢。索引的葉級資料已經基於CustomerId列值進行了排序。因此,SQL Server可以掃描索引從第一頁到最後一頁的葉子級別,並按照儲存行的順序返回這些行。SQL Server從索引的根頁開始,然後從那裡讀取第一行。該行引用具有最小鍵值的中間頁從表中引用。SQLServer讀取該頁並重復該過程,直到找到葉級上的第一頁為止。然後,SQLServer開始逐行讀取行,遍歷頁的連結串列,直到讀取所有行為止。圖2-8說明了這一過程。

 

 

 

CHAPTER 2 ■ TABLES AND INDEXES: INTERNAL STRUCTURE AND ACCESS METHODS

第2章表和索引:內部結構和訪問方法

 

Figure 2-8. Ordered index scan       

圖2-8。有序索引掃描

 

The execution plan for the preceding query shows the  Clustered Index Scan operator with the  Ordered property set to true, as shown in Figure 2-9 .  

前面查詢的執行計劃顯示了具有Ordered屬性設定為true的叢集索引掃描操作符,如圖2-9所示。

 

Figure 2-9. Ordered index scan execution plan         

圖2-9。有序索引掃描執行計劃

 

It is worth mentioning that the order by clause is not required for an ordered scan to be triggered. An ordered scan just means that SQL Server reads the data based on the order of the index key.  SQL Server can navigate through indexes in both directions, forward and backward. However, there is one important aspect that you must keep in mind: SQL Server does not use parallelism during backward index scans.

值得一提的是,觸發有序掃描不需要order by子句。有序掃描僅僅意味著SQL Server根據索引鍵的順序讀取資料。SQL Server可以在兩個方向上(向前和向後)瀏覽索引。但是,您必須記住一個重要方面:SQL Server在反向索引掃描期間不使用並行性。

 

 

CHAPTER 2 ■ TABLES AND INDEXES: INTERNAL STRUCTURE AND ACCESS METHODS

第2章 ■ 表和索引:內部結構和訪問方法

 

■ Tip   You can check scan direction by examining the INDEX SCAN or INDEX SEEK operator properties in the execution plan. Keep in mind, however, that Management Studio does not display these properties in the graphical representation of the execution plan. You need to open the Properties window to see it by selecting the operator in the execution plan and choosing the  View/Properties Window menu item or by pressing the F4 key.  

■提示  您可以通過檢查執行計劃中的INDEX SCAN或INDEX SEEK操作符屬性來檢查掃描方向。但是,請記住,Management Studio不會在執行計劃的圖形表示中顯示這些屬性。您需要開啟“屬性”視窗以通過在執行計劃中選擇運算子並選擇“檢視/屬性”視窗選單項或按F4鍵來檢視該屬性視窗。

 

The Enterprise Edition of SQL Server has an optimization feature called merry-go-round scan that allows multiple tasks to share the same index scan. Let’s assume that you have session S1, which is scanning the index. At some point in the middle of the scan, another session, S2, runs a query that needs to scan the same index. With a merry-go-round scan, S2 joins S1 at its current scan location. SQL Server reads each page only once, passing rows to both sessions.  When the S1 scan reaches the end of the index, S2 starts scanning data from the beginning of the index until the point where the S2 scan started. A merry-go-round scan is another example of why you cannot rely on the order of the index keys and why you should always specify an ORDER BY  clause when it matters. The next access method after the ordered scan is called an allocation order scan. S QL Server accesses the table data through the IAM pages, similar to how it does so with heap tables. The SELECT Name FROM dbo.Customers WITH (NOLOCK)  query and Figure  2-10  illustrate this method. Figure  2-11 shows the query execution plan.   

SQL Server的企業版有一個名為merry-go-.scan的優化特性,允許多個任務共享相同的索引掃描。假設您有會話S1,它正在掃描索引。在掃描中間的某個時刻,另一個會話S2執行需要掃描相同索引的查詢。通過旋轉木馬掃描,S2在其當前掃描位置連線S1。SQLServer只讀取每個頁面一次,將行傳遞給兩個會話。當S1掃描到達索引的結束時,S2從索引的開始開始掃描資料,直到S2掃描開始的點。旋轉木馬掃描是另一個示例,它說明了為什麼您不能依賴於索引鍵的順序,以及為什麼在需要時應該始終指定ORDER BY子句。排序掃描之後的下一個訪問方法稱為分配順序掃描。S QL Server通過IAM頁面訪問表資料,類似於使用堆表的方式。SELECTNamefromdbo.Customers WITH(NOLOCK)查詢和圖2-10說明了這種方法。圖2-11顯示了查詢執行計劃。

 

 

Figure 2-10. Allocation order scan

圖2-10。分配順序掃描

 

 

 

CHAPTER 2 ■ TABLES AND INDEXES: INTERNAL STRUCTURE AND ACCESS METHODS

第2章 ■ 表和索引:內部結構和訪問方法

 

 

Figure 2-11. Allocation order scan execution plan

圖2-11。分配順序掃描執行計劃

 

Unfortunately, it is not easy to detect when SQL Server uses an allocation order scan. Even though the Ordered property in the execution plan shows false , it indicates that SQL Server does not care whether the rows were read in the order of the index key, not that an allocation order scan was used.

不幸的是,很難檢測SQL Server何時使用分配順序掃描。儘管執行計劃中的Ordered屬性顯示為false,但它表明SQL Server並不關心行是否按索引鍵的順序讀取,而不關心使用分配順序掃描。分配順序掃描可以更快地掃描大表,儘管它有更高的啟動成本。

 

An allocation order scan can be faster for scanning large tables, although it has a higher startup cost. SQL Server does not use this access method when the table is small. Another important consideration is data consistency. SQL Server does not use forwarding pointers in tables that have a clustered index, and an allocation order scan can produce inconsistent results. Rows can be skipped or read multiple times due to the data movement caused by page splits. As a result, SQL Server usually avoids using allocation order scans unless it reads the data in READ UNCOMMITTED  or  SERIALIZABLE  transaction-isolation levels.

當表小時,SQLServer不使用此訪問方法。另一個重要的考慮因素是資料一致性。SQL Server在具有叢集索引的表中不使用轉發指標,並且分配順序掃描可能產生不一致的結果。由於分頁導致的資料移動,可以多次跳過或讀取行。因此,SQLServer通常避免使用分配順序掃描。除非它以READ UNCOMMITTED或SERIALIZABLE事務隔離級別讀取資料。

 

■ Note We will talk about page splits and fragmentation in Chapter 6 , “Index Fragmentation,” and discuss locking and data consistency in Part III, “Locking, Blocking, and Concurrency.”

■注意 我們將在第6章“索引分段”中討論分頁和分段,在第三部分“鎖定、阻塞和併發”中討論鎖定和資料一致性。

 

The last index access method is called index seek . The SELECT Name FROM dbo.Customers WHERE CustomerId BETWEEN 4 AND 7 query and Figure  2-12 illustrate the operation.

最後一個索引訪問方法稱為索引查詢。從dbo.Customers WHERE CustomerId BETWEEN 4和7查詢的SELECT Name以及圖2-12說明了該操作。

 

Figure 2-12. Index seek

圖2-12。索引查詢

 

CHAPTER 2 ■ TABLES AND INDEXES: INTERNAL STRUCTURE AND ACCESS METHODS

第2章 ■ 表和索引:內部結構和訪問方法

 

In order to read the range of rows from the table, SQL Server needs to find the row with the minimum value of the key from the range, which is 4. SQL Server starts with the root page, where the second row references the page with the minimum key value of 350. It is greater than the key value that we are looking for (4), and SQL Server reads the intermediate-level data page (1:170) referenced by the first row on the root page.

為了從表中讀取行的範圍,SQL Server需要從範圍中找到具有最小鍵值的行,即4。SQL Server從根頁面開始,其中第二行引用具有最小鍵值350的頁面。它大於我們正在尋找的鍵值(4),並且SQL Server讀取由根頁面上的第一行引用的中間級資料頁(1:170)。

 

Similarly, the intermediate page leads SQL Server to the first leaf-level page (1:176). SQL Server reads that page, then it reads the rows with CustomerIds equal to 4 and 5, and, finally, it reads the two remaining rows from the second page.

類似地,中間頁面將SQL Server引導到第一個葉級頁面(1:176)。SQLServer讀取然後,它讀取CustomerIds等於4和5的行,最後,它從第二頁讀取剩餘的兩行。

 

The execution plan is shown in Figure  2-13 .

執行計劃如圖2-13所示。

 

 

Figure 2-13. Index seek execution plan

圖2-13。索引查詢執行計劃

 

As you can guess, index seek is more efficient than index scan, because SQL Server processes just the subset of rows and data pages rather than scanning the entire table.

可以猜到,索引查詢比索引掃描更有效,因為SQL Server只處理行和資料頁的子集,而不掃描整個表。

 

Technically speaking, there are two kinds of index seek operations. The first is called a  singleton lookup , or sometimes  point-lookup , where SQL Server seeks and returns a single row. You can think about  WHERE CustomerId = 2  predicate as an example. The other type of index seek operation is called a  range scan , and it requires SQL Server to find the lowest or highest value of the key and scan (either forward or backward) the set of rows until it reaches the end of scan range. The predicate  WHERE CustomerId BETWEEN 4 AND 7  leads to the range scan. Both cases are shown as  INDEX SEEK  operations in the execution plans.

從技術上講,有兩種索引查詢操作。第一個稱為單例查詢,有時稱為點查詢,其中SQL Server查詢並返回一行。您可以想到Cuffer-Id= 2謂詞在哪裡。另一種型別的索引查詢操作稱為範圍掃描,它要求SQL Server查詢鍵的最低值或最高值,並掃描(向前或向後)行集合,直到到達掃描範圍的末尾。客戶機ID介於4和7之間的謂詞導致範圍掃描。兩種情況都顯示為執行計劃中的索引查詢操作。

 

As you can guess, it is entirely possible for range scans to force SQL Server to process a large number or even all data pages from the index. For example, if you changed the query to use a  WHERE CustomerId > 0 predicate, SQL Server would read all rows/pages, even though you would have an Index Seek operator displayed in the execution plan. You must keep this behavior in mind and always analyze the efficiency of range scans during query performance tuning.

正如您所猜到的,範圍掃描完全可能迫使SQL Server處理索引中的大量資料頁甚至所有資料頁。例如,如果將查詢更改為使用WHERE CustomerId>0謂詞,SQL Server將讀取所有行/頁,儘管在執行計劃中將顯示Index Seek操作符。您必須牢記這種行為,並在查詢效能優化期間始終分析範圍掃描的效率。

 

There is a concept in relational databases called SARGable predicates , which stands for  Search Argument able . The predicate is SARGable if SQL Server can utilize an index seek operation, if an index exists. In a nutshell, predicates are SARGable when SQL Server can isolate the single value or range of index key values to process, thus limiting the search during predicate evaluation. Obviously, it is beneficial to write queries using SARGable predicates and utilize index seek whenever possible.

在關係資料庫中有一個稱為SARGable謂詞的概念,它代表Search Argument able。如果SQL Server可以利用索引查詢操作(如果存在索引),則謂詞是SARGable。簡言之,當SQL Server可以隔離要處理的索引鍵值的單個值或範圍時,謂詞就是SARGable,從而限制了謂詞評估期間的搜尋。顯然,使用SARGable謂詞編寫查詢並儘可能利用索引查詢是有益的。

 

SARGable predicates include the following  operators:  = , > , >= , < , <= , IN , BETWEEN , and LIKE (in case of prefix matching). Non-SARGable operators include NOT , <> , LIKE (in case of non-prefix matching), and NOT IN .

SARGable謂詞包括下列操作符:=、>、>=、<、<=、IN、BETWEEN和LIKE(在字首匹配的情況下)。非SARGable操作符包括NOT、<>、LIKE(在非字首匹配的情況下)和NOT IN。

 

Another circumstance for making predicates non-SARGable is using functions or mathematical calculations against the table columns. SQL Server has to call the function or perform the calculation for every row it processes. Fortunately, in some of cases you can refactor the queries to make such predicates SARGable. Table  2-1  shows a few examples of this.

使謂詞不可SARGable的另一種情況是對錶列使用函式或數學計算。SQL Server必須呼叫該函式或對其處理的每行執行計算。幸運的是,在某些情況下,您可以重構查詢以使得這樣的謂詞SARGable。表2-1顯示了一些例子。

 

 

 

 

 

 

 

 

 

 

CHAPTER 2 ■ TABLES AND INDEXES: INTERNAL STRUCTURE AND ACCESS METHODS

第2章 ■ 表和索引:內部結構和訪問方法

 

Another important factor that you must keep in mind is type conversion . In some cases, you can make predicates non-SARGable by using incorrect data types. Let’s create a table with a varchar column and populate it with some data, as shown in Listing 2-6 .

你必須記住的另一個重要因素是型別轉換。在某些情況下,可以使用不正確的資料型別使謂詞不可SARGable。讓我們建立一個包含varchar列的表,並用一些資料填充它,如清單2-6所示。

 

Listing 2-6. SARG predicates and data types: Test table creation

清單2-6。SARG謂詞和資料型別:測試表建立

 

The clustered index key column is defined as varchar, even though it stores integer values. Now, let’s run two selects, as shown in Listing 2-7 , and look at the execution plans.

叢集索引鍵列被定義為varchar,即使它儲存整數值。現在,讓我們執行兩個選擇,如清單2-7所示,並檢視執行計劃。

CHAPTER 2 ■ TABLES AND INDEXES: INTERNAL STRUCTURE AND ACCESS METHODS

第2章 ■ 表和索引:內部結構和訪問方法

 

Listing 2-7. SARG predicates and data types: Select with integer parameter

清單2-7。SARG謂詞和資料型別:用整數引數選擇

 

declare

 @IntParam int = '200'

select * from dbo.Data where VarcharKey = @IntParam;

Select * from dbo.Data where VarcharKey = convert(varchar(10),@IntParam);

 

As you can see in Figure  2-14 , in the case of the integer parameter, SQL Server scans the clustered index, converting varchar to an integer for every row. In the second case, SQL Server converts the integer parameter to a varchar at the beginning and utilizes a much more efficient clustered index seek operation.

如圖2-14所示,在整數引數的情況下,SQL Server掃描叢集索引,將每行的varchar轉換為整數。在第二種情況下,SQL Server在開始時將整數引數轉換為varchar,並利用更有效的叢集索引查詢操作。

 

 

Figure 2-14. SARG predicates and data types: Execution plans with integer parameter

圖2-14。SARG謂詞和資料型別:整數引數的執行方案

 

■ Tip  Pay attention to the column data types in the join predicates. Implicit or explicit data type conversions can significantly decrease the performance of the queries.

■ 提示 注意連線謂詞中的列資料型別。隱式或顯式資料型別轉換可以顯著降低查詢的效能。

 

You will observe very similar behavior in the case of unicode string parameters. Let’s run the queries shown in Listing 2-8 . Figure  2-15 shows the execution plans for the statements.

在unicode字串引數的情況下,您將觀察到非常類似的行為。讓我們執行清單2-8所示的查詢。圖2-15顯示了語句的執行計劃。

 

Listing 2-8. SARG predicates and data types: Select with string parameter

清單2-8。SARG謂詞和資料型別:用字串引數選擇

 

select * from dbo.Data where VarcharKey = '200';

select * from dbo.Data where VarcharKey = N'200'; -- unicode parameter

 

 

 

CHAPTER 2 ■ TABLES AND INDEXES: INTERNAL STRUCTURE AND ACCESS METHODS

第2章■ 表和索引:內部結構和訪問方法

 

 

 

Figure 2-15. SARG predicates and data types: Execution plans with string parameter

圖2-15。SARG謂詞和資料型別:具有字串引數的執行計劃

 

 

As you can see, a unicode string parameter is non-SARGable for varchar columns. This is a much bigger issue than it appears to be. While you rarely write queries in this way, as shown in Listing 2-8 , most application development environments nowadays treat strings as unicode. As a result, SQL Server client libraries generate unicode ( nvarchar ) parameters for string objects unless the parameter data type is explicitly specified as varchar . This makes the predicates non-SARGable, and it can lead to major performance hits due to unnecessary scans, even when varchar columns are indexed.

正如您所看到的,Unicode字串引數對於VARCHAR列是非SGARABLE。這是一個比看上去更大的問題。雖然很少以這種方式編寫查詢,如清單2-8所示,但是現在大多數應用程式開發環境將字串視為unicode。因此,SQL Server客戶端庫為字串物件生成unicode(nvarchar)引數,除非引數資料型別明確指定為varchar。這就使得謂語不可理解,它可以導致主語。即使對varchar列進行索引,由於不必要的掃描也會導致效能下降。

 

■ Important Always specify parameter data types in client applications. For example, in ADO.Net, use Parameters.Add("@ParamName",SqlDbType.Varchar, <Size>).Value = stringVariable instead of Parameters.Add("@ParamName").Value = stringVariable overload. Use mapping in ORM frameworks to explicitly specify non-unicode attributes in the classes.

■ 重要的是始終在客戶端應用程式中指定引數資料型別。例如,在ADO.NET中,使用Parameters.Add("@ParamName",SqlDbType.Varchar, <Size>).Value = stringVariable instead of

Parameters.Add("@ParamName").Value = stringVariable overload. 在ORM框架中使用對映來顯式地指定類中的非unicode屬性。

 

It is also worth mentioning that varchar parameters are SARGable for nvarchar unicode data columns.

還值得一提的是,對於nvarchar unicode資料列,varchar引數是SARGable。

 

 

Composite Indexes

綜合指數

 

Indexes with multiple key columns are called composite (or compound) indexes . The data in the composite indexes is sorted on a per-column basis from leftmost to rightmost columns. Figure 2-16 shows the structure of a composite index.

具有多個鍵列的索引稱為複合(或複合)索引。複合索引中的資料按每列從最左到最右的列進行排序。圖2-16顯示了複合索引的結構。