Clustered، Nonclustered، Filtered و Columnstore Indexها
یادداشت حقوقی: کاربر حق ترجمه و بازنشر این اثر را برای پروژه تأیید کرده است.PAGE-262فصل ۸ — Indexes and Statistics
SQL Server انواع مختلف Index را برای بهبود دسترسی به داده فراهم میکند و Statistics را برای برآورد Cardinality و انتخاب Plan نگه میدارد. این بخش با Clustered و Nonclustered Index شروع میشود و سپس به Covering، Filtered و Columnstore میرسد.
PAGE-263Heap و Clustered Index
جدولی که Clustered Index ندارد Heap است. رکوردهای Heap روی Pageها قرار میگیرند و Row Identifier برای یافتن رکورد لازم است. Heap در برخی الگوها مناسب است، اما جستوجوی ترتیبی یا Range اغلب به Scan بیشتری نیاز دارد. Clustered Index داده را در Leaf Level بر اساس کلید مرتب میکند.
Figure 8-1 — شکل/تصویر منبع، صفحه PDF 263PAGE-264Clustered Index ساختار B-tree دارد: Root و Intermediate Level حاوی کلیدها و Pointerها هستند و Leaf Level خودِ Data Pageهاست. برای یافتن یک مقدار، موتور از Root به Leaf حرکت میکند. در Range Scan، پس از رسیدن به نقطه شروع، Pageهای Leaf به ترتیب پیمایش میشوند.
Figure 8-2 — شکل/تصویر منبع، صفحه PDF 264PAGE-265برای Range Query ممکن است Optimizer ترکیبی از Seek تا اولین مقدار و سپس Scan ترتیبی Leaf Level را انتخاب کند. کیفیت کلید Clustered اهمیت زیادی دارد: کلید Narrow، Stable، Unique و ترجیحاً Ever-Increasing باعث کاهش سربار Nonclustered Indexها و Page Split میشود.
PAGE-266NEWSEQUENTIALID() میتواند برای GUIDهای ترتیبیتر مفید باشد، اما پس از Restart ممکن است توالی نسبت به مقادیر پیشین تغییر کند. همچنین کلید Clustered در Leafهای Nonclustered Index نگهداری میشود؛ بنابراین کلید پهن، همه NCIها را بزرگتر میکند.
PAGE-267ساخت Clustered Index
CREATE DATABASE Chapter8;
GO
USE Chapter8;
GO
CREATE TABLE dbo.CIDemo
(
ID int IDENTITY,
DummyText varchar(30)
);
CREATE UNIQUE CLUSTERED INDEX CI_CIDemo ON dbo.CIDemo(ID);
فایلهای Database در محیط خود باید با مسیرهای صحیح تنظیم شوند. Index میتواند همزمان با CREATE TABLE/Constraint یا با CREATE INDEX ساخته شود.
Table 8-1 — بازنمایی متن فنی جدول منبع--- PDF PAGE 267 ---
250
Listing 8-1. Creating a Clustered Index
--Create Chapter8 Database
CREATE DATABASE Chapter8
ON PRIMARY
( NAME = N'Chapter8', FILENAME =
N'F:\Program Files\Microsoft SQL Server\MSSQL15.PROSQLADMIN\MSSQL\DATAChapter8.mdf'),
FILEGROUP [MEM] CONTAINS MEMORY_OPTIMIZED_DATA DEFAULT
( NAME = N'MEM', FILENAME = N'H:\DATA\CH08')
LOG ON
( NAME = N'Chapter8_log', FILENAME =
N'E:\Program Files\Microsoft SQL Server\MSSQL15.PROSQLADMIN\MSSQL\DATAChapter8_log.ldf') ;
GO
USE Chapter8
GO
--Create CIDemo table
CREATE TABLE dbo.CIDemo
(
ID INT IDENTITY,
DummyText VARCHAR(30)
) ;
GO
--Create clustered index
CREATE UNIQUE CLUSTERED INDEX CI_CIDemo ON dbo.CIDemo([ID]) ;
GO
When creating an index, you have a number of WITH options that you can specify.
These options are outlined in Table 8-1.
Chapter 8 Indexes and Statistics
--- PDF PAGE 268 ---
251
Table 8-1. Clustered Index WITH Options
Option
Description
MAXDOP
Specifies how many cores are used to build the index. Each core that is
used builds its own portion of the index. The trade-off is that a higher
MAXOP builds the index faster, but a lower MAXDOP means the index is
built with less fragmentation.
FILLFACTOR
Specifies how much free space should be left in each page of the leaf
level of the index. This can help reduce fragmentation caused by inserts
at the expense of having a wider index, which requires more IO to read.
For a clustered index, with a nonchanging, ever-increasing key, always
set this to 0, which means 100% full minus enough space for one row.
PAD_INDEX
Applies the fill factor percentage to the intermediate levels of the B-tree.
STATISTICS_
NORECOMPUTE
Turns on or off the automatic updating of distribution statistics. Statistics
are discussed later in this chapter.
SORT_IN_TEMPDB
Specifies that the intermediate sort results of the index should be stored
in TempDB. When you use this option, you can offload IO to the spindles
hosting TempDB, but this is at the expense of using more disk space.
Cannot be ON if RESUMABLE is ON.
STATISTICS_
INCREMENTAL
Specifies if statistics should be created per partition. Limitations to this
are discussed later in this chapter.
DROP_EXISTING
Used to drop and rebuild the existing index with the same name.
IGNORE_DUP_KEY
When you enable this option, an INSERT statement that tries to insert a
duplicate key value into a unique index will not fail. Instead, a warning is
generated and only the rows that break the unique constraint fail.
ONLINE
Can be set as ON or OFF, with a default of OFF. Specifies if the entire
table and indexes should be locked for the duration of the index build or
rebuild. If ON, then queries are still able to access the table during the
operation. This is at the expense of the time it takes to build the index.
For clustered indexes, this option is not available if the table contains
LOB data.*
(continued)
Chapter 8 Indexes and Statistics
--- PDF PAGE 269 ---
252
As mentioned earlier in this chapter, if you create a primary key on a table, then
unless you specify the NONCLUSTERED keyword, or a clustered index already exists, a
clustered index is created automatically to cover the column(s) of the primary key. Also,
remember that at times you may wish to move the clustered index to a more suitable
column if the primary key is wide or if it is not ever-increasing.
In order to achieve this, you need to drop the primary key constraint and then re-
create it using the NONCLUSTERED keyword. This forces SQL Server to cover the primary
key with a unique nonclustered index. Once this is complete, you are able to create the
clustered index on the column of your choosing.
If you need to remove a clustered index that is not covering a primary key, you can
do so by using the DROP INDEX statement, as demonstrated in Listing 8-2, which drops
the clustered index that we created in the previous example.
Listing 8-2. Dropping the Index
DROP INDEX CI_CIDemo ON dbo.CIDemo ;
Table 8-1. (continued)
Option
Description
OPTIMIZE_FOR_
SEQUENTIAL_KEY
Optimizes high concurrency inserts, where the index key is sequential.
Introduced in SQL Server 2019, this feature is designed for indexes that
suffer from last-page insert contention.
RESUMABLE
Can be set as ON or OFF, with a default of OFF. Specifies if the index
creation or build can be paused and resumed or can be resumed after a
failure. Can only be set to ON if ONLINE is set to ON.
MAX_DURATION
Specifies, in minutes, the maximum duration that an index rebuild or
rebuild will execute for, before pausing. Can only be specified if ONLINE
is set to ON and RESUMABLE is set to ON.
ALLOW_ROW_LOCKS
Specifies that you can take row locks out when accessing the table. This
does not mean that they definitely will be taken.
ALLOW_PAGE_LOCKS
Specifies that you can take page locks out when accessing the table.
This does not mean that they definitely will be taken.
*Spatial data is regarded as LOB data.
Chapter 8 Indexes and Statistics
|
PAGE-268گزینههای ساخت Index
گزینههای مهم Clustered Index| گزینه | کاربرد |
|---|
| MAXDOP | تعداد Processorهای مورد استفاده برای Build |
| FILLFACTOR | درصد پرشدن Leaf Page و فضای آزاد برای رشد |
| SORT_IN_TEMPDB | انجام عملیات Sort در TempDB |
| ONLINE | کاهش Blocking هنگام Build/Rebuild در Edition/عملیات پشتیبانیشده |
| DATA_COMPRESSION | اعمال ROW/PAGE روی Index یا Partition |
| DROP_EXISTING | جایگزینی Index موجود با ساختار جدید |
PAGE-269Index را میتوان با DROP INDEX حذف کرد. هنگام تغییر Clustered Index باید به هزینه بازسازی Nonclustered Indexها توجه کرد، زیرا Row Locator آنها به کلید Clustered وابسته است. بعضی گزینهها مثل ONLINE، MAXDOP و SORT_IN_TEMPDB روی مدت زمان و مصرف Resource اثر قابل توجه دارند.
PAGE-270Nonclustered Index
Nonclustered Index یک B-tree جدا از Data است. Leaf Level آن Keyهای NCI و Row Locator را نگه میدارد. اگر جدول Clustered باشد Row Locator همان Clustered Key است؛ اگر Heap باشد RID استفاده میشود. NCI امکان Seek سریع روی ستونهایی را میدهد که ترتیب فیزیکی اصلی جدول بر اساس آنها نیست.
Figure 8-3 — شکل/تصویر منبع، صفحه PDF 270PAGE-271Covering Index
وقتی تمام ستونهای لازم Query در Key یا INCLUDE یک NCI موجود باشند، Query Covered است و برای گرفتن ستون اضافی به Lookup روی Clustered Index/Heap نیاز ندارد. INCLUDE اجازه میدهد ستونهای خروجی در Leaf ذخیره شوند بدون آنکه بخشی از Key و محدودیت اندازه کلید باشند.
PAGE-272در NCI، ستونهای Key برای جستوجو و مرتبسازی و ستونهای INCLUDE برای پوشش خروجی مناسباند. افزودن ستون بیش از حد، حجم Index و هزینه DML را افزایش میدهد. طراحی باید تعادل میان Read Performance، Storage و هزینه Insert/Update/Delete را حفظ کند.
Figure 8-4 — شکل/تصویر منبع، صفحه PDF 272PAGE-273ایجاد داده آزمایشی و Nonclustered Index
کتاب جداول CustomersDisk و OrdersDisk را با داده آزمایشی میسازد و سپس NCI روی Balance ایجاد میکند. دادهها با CTE و انتخاب تصادفی Name/Number تولید میشوند تا Queryهای مثال روی حجم قابل توجهی اجرا شوند.
PAGE-274CustomersDisk شامل CustomerID، نام، Address ID، CreditLimit و Balance است. Primary Key روی CustomerID قرار میگیرد. سپس دادههای تصادفی در جدول درج میشوند تا تأثیر NCI و Covering Index قابل مشاهده باشد.
PAGE-275OrdersDisk شامل OrderNumber، OrderDate، CustomerID، ProductID، Quantity، NetAmount و DeliveryDate است. داده سفارش نیز از مجموعه اعداد و Customerهای ایجادشده تولید میشود. این جدول مبنای بسیاری از مثالهای Index در ادامه فصل است.
PAGE-276پس از درج داده، Tableهای موقت پاک و Foreign Key میان OrdersDisk.CustomerID و CustomersDisk.CustomerID اضافه میشود. سپس NCI اولیه روی Balance ساخته میشود.
PAGE-277INCLUDE و Filtered Index
CREATE NONCLUSTERED INDEX NCI_Balance
ON dbo.CustomersDisk(Balance)
INCLUDE(LastName, FirstName)
WITH (DROP_EXISTING = ON);
Filtered Index فقط زیرمجموعهای از Rowها را نگه میدارد و میتواند برای Queryهای انتخابی بسیار کوچکتر و ارزانتر باشد. Filter با WHERE تعریف میشود و محدودیتهایی دارد؛ Predicate باید ساده و قابل پشتیبانی باشد.
PAGE-278CREATE NONCLUSTERED INDEX NonDeliveredItems
ON dbo.OrdersDisk(DeliveryDate)
WHERE DeliveryDate IS NULL;
Indexهای تخصصی و Columnstore
علاوه بر B-tree، SQL Server برای Memory-Optimized و Data Warehouse ساختارهای تخصصی دارد. Columnstore به جای ذخیره Row کامل روی Page، داده را ستونی سازماندهی میکند و برای Queryهای تحلیلی روی جدولهای بزرگ طراحی شده است.
PAGE-279Columnstore رکوردها را در Rowgroupهای حدود 102,400 تا 1,048,576 سطری سازمان میدهد. هر Rowgroup به Column Segmentها تقسیم و با VertiPaq فشرده میشود. Metadata هر Segment به Elimination کمک میکند و Batch Mode امکان پردازش دستهای حدود هزار Row را فراهم میکند؛ در نتیجه I/O، Memory و CPU برای workload تحلیلی کاهش مییابد.
Figure 8-5 — شکل/تصویر منبع، صفحه PDF 279PAGE-280Clustered Columnstore Index
در Clustered Columnstore کل جدول بهصورت Columnstore ذخیره میشود. Insertهای کوچک ابتدا ممکن است وارد Deltastore Rowstore شوند و پس از رسیدن به حد مناسب، Tuple Mover آنها را فشرده و به Rowgroup منتقل میکند. Query Engine Deltastore و Rowgroupهای فشرده را بهصورت شفاف یک مجموعه واحد میبیند.
Figure 8-6 — شکل/تصویر منبع، صفحه PDF 280