تفاوت Primary Key و Clustered Index

تفاوت Primary Key و Clustered Index

نوشته شده توسط: تورج عزیزی
۳۰ آبان ۱۳۹۴
زمان مطالعه: 10 دقیقه
1.5
(6)

مقدمه

در این مقاله قصد دارم شما رو با یک موضوع مهم در SQL Server که بیشتر مواقع برنامه نویس ها و DBA ها در درک اون مشکل دارند آشنا کنم. این موضوع تفاوت بین Primary Key و Clustered Index است.

Primary Key چیست؟

اجازه دهید ابتدا در مورد خود قید Primary Key صحبت کنیم. همانطور که می توان از نام این قید فهمید، شما با این قید از SQL Server می خواهید که در یک ستون یا گروهی از ستون ها فقط مقدار یونیک وارد شود. اسکریپت زیر تعریفی ساده  از یک جدول نشان می دهد که در آن  قید Primary Key روی ستون Col1 جدول تعریف شده است.

CREATE TABLE Foo
(
Col1 INT NOT NULL PRIMARY KEY,
Col2 INT NOT NULL,
Col3 INT NOT NULL
)
GO
حالا وقتی در این جدول رکورد درج می کنید، SQL Server از یونیک بودن مقادیر وارده شده در ستون Col1 اطمینان حاصل می کند. حالا اگر سعی کنید مقادیر تکراری وارد کنید، SQL Server پیام خطا صادر می کند:
-- Try to insert a duplicate value
INSERT INTO Foo Values (1, 1, 1), (1, 2, 2)
GO
Msg 2627, Level 14, State 1, Line 9 Violation of PRIMARY KEY constraint ‘PK__Foo__A259EE544224D12A’. Cannot insert duplicate key in object ‘dbo.Foo’. The duplicate key value is (1). The statement has been terminated.
قید Primary Key خودش در سطح منطقی تعریف می شود- شما فقط به SQL Server می گوئید در این ستون مقادیر یونیک می خواهید. اما SQL Server این قید را در سطح فیزیکی هم باید تامین کند – در ساختمان داده هایی که شما در آنها داده هایتان را ذخیره می کنید.
در مورد SQL Server در سطح فیزیکی این کار توسط ایندکس ها انجام می شود : توسط یک Clustered Index یا NonClustered Index.

تحمیل قید Primary Key

و قتی شما قید Primary Key  را مشخص می کنید، SQL Server به طور پیش فرض این قید را با استفاده از یک Unique Clustered Index در سطح فیزیکی تحمیل می کند. اگر به sys.indexes نگاهی بیندازید می بینید که SQL Server یک Unique Clustered Index ایجاد کرده است که برای تحمیل قید Primary Key  استفاده شده است.
 -- SQL Server generates by default a Unique Clustered Index
SELECT * FROM sys.indexes
WHERE object_id = OBJECT_ID('Foo')
GO
همانطوری که گفتم به طور پیش فرض Unique Clustered Index ایجاد شده است. شما می توانید تحمیل قید Primary Key را با استفاده از NonClustered Index انجام دهید:

-- Enforces the Primary Key constraint with a Unique Non-Clustered Index
CREATE TABLE Foo1
(
Col1 INT NOT NULL PRIMARY KEY NONCLUSTERED,
Col2 INT NOT NULL,
Col3 INT NOT NULL
)
GO
وقتی قید  Primary Key را مشخص می کنید می توانید دو گزینه را مشخص کنید:
  • Clustered
  • Nonclustered
گزینه Clustered پیش فرض است، بنابراین لزومی بر تعیین آن نیست. حالا اگر دوباره به sys.indexes نگاه کنید، متوجه می شوید که یک HEAP در مقابل دارید (جدولی بدون Clustered Index) و اینکه SQL Server یک ایندکس Nonclustered اضافی برای تحمیل قید Primary Key ایجاد کرده است.
-- SQL Server has generated now a Unique Non-Clustered Index to
-- enforce the Primary Key constraint
SELECT * FROM sys.indexes
WHERE object_id = OBJECT_ID('Foo1')
GO

Primary Key  <> Clustered Index

نتیجه اینکه همیشه Primary Key و Clustered Index در SQL Server با هم برابر  نیستند. این یک پیش فرض است و شما می توانید آن را تغییر دهید. قید Primary Key در سطح منطقی است و ساختار ایندکس در سطح فیزیکی برای تحمیل خود قید استفاده می شود.

چه رتبه ای می‌دهید؟

میانگین 1.5 / 5. از مجموع 6

اولین نفر باش

title sign
معرفی نویسنده
مقالات
17 مقاله توسط این نویسنده
محصولات
0 دوره توسط این نویسنده
title sign
دیدگاه کاربران

  • درود
    واقعا عالی توضیح داده بودید.
    دیروز Cluster Index و NON Cluster Index و Unique بودنشان و ارتباطشون با PK رو کلا قاطی کردم.
    شروع به سیرچ و خوندن مقالات کردم ولی بی فایده بود.
    اما مقاله شما کاملا همه چیز رو برام سر جاش نشوند به خصوص که کوئری ها رو هم آورده بودید.
    خیلی خیلی ممنون

  • درود
    واقعا عالی توضیح داده بودید.
    دیروز Cluster Index و NON Cluster Index و Unique بودنشان و ارتباطشون با PK رو کلا قاطی کردم.
    شروع به سیرچ و خوندن مقالات کردم ولی بی فایده بود.
    اما مقاله شما کاملا همه چیز رو برام سر جاش نشوند به خصوص که کوئری ها رو هم آورده بودید.
    خیلی خیلی ممنون

  •   با سلام و خسته نباشید خدمت شما

    به چه صورت می توان حجم non cluster index را بدست آورد یعنی اون page های اضافی که می زند و مسائل دیگر؟

    آیا کوئری برای این منظور وجود دارد؟

    ممنون می شوم من را راهنمایی کنید.

    با تشکر

    •     سلام چندین روش برای انجام ایتکار وجود دارد یکی از آنها

      SELECT
      OBJECT_NAME(i.OBJECT_ID) AS TableName,
      i.name AS IndexName,
      i.index_id AS IndexID,
      8 * SUM(a.used_pages) AS ‘Indexsize(KB)’
      FROM sys.indexes AS i
      JOIN sys.partitions AS p ON p.OBJECT_ID = i.OBJECT_ID AND p.index_id = i.index_id
      JOIN sys.allocation_units AS a ON a.container_id = p.partition_id
      GROUP BY i.OBJECT_ID,i.index_id,i.name
      ORDER BY OBJECT_NAME(i.OBJECT_ID),i.index_id
  •   با سلام و خسته نباشید خدمت شما

    به چه صورت می توان حجم non cluster index را بدست آورد یعنی اون page های اضافی که می زند و مسائل دیگر؟

    آیا کوئری برای این منظور وجود دارد؟

    ممنون می شوم من را راهنمایی کنید.

    با تشکر

    •     سلام چندین روش برای انجام ایتکار وجود دارد یکی از آنها

      SELECT
      OBJECT_NAME(i.OBJECT_ID) AS TableName,
      i.name AS IndexName,
      i.index_id AS IndexID,
      8 * SUM(a.used_pages) AS ‘Indexsize(KB)’
      FROM sys.indexes AS i
      JOIN sys.partitions AS p ON p.OBJECT_ID = i.OBJECT_ID AND p.index_id = i.index_id
      JOIN sys.allocation_units AS a ON a.container_id = p.partition_id
      GROUP BY i.OBJECT_ID,i.index_id,i.name
      ORDER BY OBJECT_NAME(i.OBJECT_ID),i.index_id