تغییرات اخیر

در اینجا اطلاعیه‌ها، نسخه‌ها و تغییرات جدید لیارا فهرست می‌شوند.

چگونگی ایجاد Primary Key در دیتابیس


۱ مرداد ۱۳۹۹

وقتی پای طراحی یک دیتابیس به میان می‌آید، اولین سوالی که باید از خودمان بپرسیم این است: «هویت هر ردیف از جدول را چگونه مشخص می‌کنم؟»
در نگاه اول، این شاید سوال ساده‌ای به نظر برسد، اما اگر کمی دقیق‌تر نگاه کنیم، این همان جایی است که داستان واقعی آغاز می‌شود. انتخاب کلید اصلی در واقع مثل تعریف هویت برای موجودیت‌های دیتابیس است؛ تصمیمی که در ظاهر فنی به نظر می‌رسد اما ریشه‌ای عمیق در منطق و پایداری سیستم دارد.
در این مقاله از یک بحران هویت شروع می‌کنیم، درست شبیه انسان‌ها، و قدم‌به‌قدم به این سوال پاسخ می‌دهیم که چطور باید کلید اصلی (Primary Key) را انتخاب کنیم. با مثالی ملموس، این مفهوم را بررسی کرده و در نهایت با چند سناریوی واقعی از ساخت کلید اصلی در جدول‌های مختلف دیتابیس، به درک بهتری از این موضوع می‌رسیم.

در ادامه خواهید خواند:

  • چگونه کلید اصلی را انتخاب کنیم؟
  • یک مثال واقعی!
  • تعریف جداول در MySQL
  • تعریف جداول در PostgreSQL
  • جمع بندی
Primary Key

چگونه کلید اصلی را انتخاب کنیم؟

شاید به این فکر کنید که تنها در زندگی است که دچار بحران هویت می‌شویم، اما این درست نیست. وقتی می‌خواهیم دیتابیسی را ایجاد کنیم، همه چیز یک جور بحران هویت است و آن تنها دلیلی است که ما به کلید اصلی نیاز داریم. (آن‌ها هدف را پیدا می‌کنند و به ما می‌گویند تا چگونه بقیه را پیدا کنیم.)

تصور کنید شما رئیس جمهور و یا هر شخص تصمیم گیرنده در امور یک کشور هستید و قصد دارید تا شهروندان خود را به صورت دیجیتال و با یک ویژگی یکتا از یکدیگر تشخیص دهید. پس شما یک دیتابیس با تمام ویژگی‌هایی که آن‌ها دارند ایجاد می‌کنید. به طور مثال دیتابیسی با فیلدهای Last Name، First Name و Passport Number در نظر می‌گیرید.

First Name
Last Name
Passport Number

از میان این ۳ فیلد، فیلد Passport Number را برای کلید اصلی و متمایز کردن افراد از یکدیگر انتخاب می‌کنید. شما می‌دانید تمام چیزی که نیاز دارید پاسپورت است که شامل آدرس و تمام چیز‌های ضروری دیگر است. همچنین Passport Number یکتا است، پس تا به اینجای کار فکر می‌کنید که همه چیز درست است و این سیستم و دیتابیس را بر اساس این کلید اصلی، یعنی Passport Number ایجاد می‌کنید.

بعد گذشت چند سال از طراحی سیستم و دیتابیس فعلی، با یک مشکل روبرو می‌شوید و آن هم این است که کشور شما دچار بحران در تشخیص هویت اشخاص می‌شود. منظور از بحران هویت در اینجا چیست؟ در واقع پاسپورت هر شخص بعد از گذشت مدت محدودی منقضی می‌شود. آن شخص تقاضای پاسپورت جدید می‌دهد. اما نکته اینجاست که به ازای هر پاسپورت جدید یک Passport Number جدید تولید می‌شود. در واقع کلید اصلی شخص، بعد از گذشت مدتی به طور مثال ۴ سال عوض می‌شود و در همین حین سایر سیستم‌های متصل به این دیتابیس از همان کلید اصلی قدیمی استفاده می‌کنند که بعد از تغییر Passport Number یا کلید اصلی، چنین شخصی با آن Passport Number وجود ندارد. در واقع از کلید اصلی و یا IDیی استفاده می‌کنند که به هیچ شخصی اشاره نمی‌کند. با همه این تفاسیر به این نکته پی می‌بریم که یکتا بودن مقدار یک فیلد کافی نیست. در واقع برای انتخاب کلید اصلی به فیلدی نیاز داریم که در طول استفاده از آن دیتابیس و جدول، مقدارش تغییر نکند. یعنی از تولد تا مرگ یک سیستم این مقدار ثابت باشد.

از طرف دیگر به این قضیه پی می‌برید که تعداد زیادی از شهروندان شما اصلا پاسپورت ندارند. در این حالت نمی‌توانید افرادی را وارد سیستم کنید در حالی که می‌خواهید کلید اصلی آن‌ها را برابر Null قرار دهید. حتی اگر هم وارد سیستم کنید چگونه می‌خواهید یک شخص با کلید اصلی Null را از سایرین تشخیص دهید؟ پس هر ردیف در جدول دیتابیس باید یک هویت و یا ID منحصر به فرد خودش را داشته باشد.

DBaaS چیست؟ درک مفهوم دیتابیس به عنوان یک سرویس
DBaaS چیست؟

بعد از مواجه شدن با این دو مشکل، نیاز داریم که یک فیلد مشخص کننده و تعیین کننده هویت هر شخص را ایجاد کنیم که در وهله اول در طول زمان تغییر نکند و در وهله دوم هر فرد شامل آن خصوصیت باشد. به طور مثال در هند این قضیه با کارتی به نام Adhaar Card و در آمریکا با Social Security Number حل شده است. پس اگر حالا قصد ایجاد دیتابیس را دارید، می‌توانید از این‌ها برای کلید اصلی استفاده کنید.

گاهی اوقات شما کلیدی مانند دو مثال قبل ندارید و یا کشوری را در نظر بگیرید که هنوز چیزی به نام Social Security Number ندارند و در عین حال می‌خواهند به ازای هر شهروند یک رکورد در دیتابیس خود داشته باشند. در این وضعیت یا باید یک SSN جدید ایجاد کنند و یا از یک کلید جایگزین استفاده کنند. کلید جایگزین هیچ معنایی در دنیای واقعی ندارد و تنها عدد و مقداری در دیتابیس است. با توجه به این نکته جدول مثال اول‌مان به شکل زیر تغییر می‌کند:

userID
First Name
Last Name
Passport Number

Passport Numberها یکتا هستند و هرگاه بخواهید یک شخص را از سایر اشخاص تشخیص دهید، می‌توانید از Passport Number استفاده کنید. اما فیلد userID هیچ وقت عوض نخواهد شد و از طرف دیگر Passport Number تغییر خواهد کرد اما به هر حال همیشه یکتاست. در نتیجه همیشه به هر شخصی که پاسپورت داشته باشد یک Passport Number داده خواهد شد. userID جایگزینی برای SSN در این کشور فرضی ما است که برای اشخاص چنین چیزی وجود ندارد. 

اما حقیقت این است که Passport Numberی که تغییر نکند، می‌تواند کلید اصلی ما باشد. این تنها یک تشخیص منطقی است که باید روی آن فکر شود. مهم‌ترین نکته به هنگام انتخاب کلید اصلی این است که آیا به موضوع بحران هویت و یا تشخیص هر فرد از یکدیگر، فکر کرده‌ایم؟ آیا امکان‌پذیر است که شخصی در آینده‌ای چه دور چه نزدیک کلید اصلی خودش را تغییر دهد؟ آیا وضعیتی پیش می‌آید که شخصی کلید اصلی برای خود نداشته باشد؟ آیا حالتی اتفاق خواهد افتاد که ۲ یا تعداد بیشتری از اشخاص، کلید اصلی یکسان داشته باشند؟

در این مثال از مردم یک کشور استفاده کردیم زیرا بحث هویت و یا ID هر ردیف در دیتابیس ملموس‌تر می‌شد و این را هم می‌دانیم که هر شخص، باید یک هویت و ID داشته باشد که از اشخاص دیگر متفاوت باشد، اما این طرز فکر در مورد مردم یک کشور را به مدل خود برای دیتابیس سیستم‌تان مرتبط کنید. از تشابه موجود بین مدل خود و این مثال استفاده کنید تا بهتر بتوانید کلید اصلی را انتخاب کنید و به این نکته هم توجه کنید که در جداول دیتابیس، هر ردیف یک ‌ID یکتا نیاز دارد و این همان دلیلی است که به کلید اصلی برای هر جدول نیاز داریم.

آموزش بکاپ‌گیری از دیتابیس MySQL در سرور مجازی اوبونتو 24.04
بکاپ‌گیری از دیتابیس MySQL

این نکته را هم در خاطر داشته باشید که گاهی اوقات برای ساخت کلید اصلی می‌توانیم از مقدار چند فیلد استفاده کنیم که به این نوع کلید، کلید مرکب یا ترکیبی می‌گویند.

حالا زمان آن رسیده است که کلید اصلی را در مثال‌های واقعی تعیین کنیم. در اینجا نیاز است تنها دو کار انجام دهید:

  1. کلید اصلی را تشخیص دهید.
  2. یاد بگیرید که چگونه کلید اصلی را در دیتابیس تعریف کنید.

یک مثال واقعی!

بیایید در نظر بگیریم یک استارت‌آپ در حوزه حمل و نقل مانند Flexport دارید. یک سری بسته دارید که نیاز است آن‌ها را از جایی تحویل بگیرید و به جای دیگری توسط کشتی‌ها منتقل کنید. علاوه بر این، مشتری‌هایی دارید که چنین بسته‌هایی را سفارش می‌دهند.

پس به یک جدول برای مشتریان،‌ یک جدول برای بسته‌ها و در انتها یک جدول برای انتقال بسته‌ها که مشخص می‌کند هر بسته در هر لحظه کجاست و چه وضعیتی دارد، نیاز داریم. به فیلد‌هایی که برای هر جدول نیاز دارید فکر کنید و این که در هر جدول کدام فیلد باید کلید اصلی باشد. اگر شما به عنوان مهندس در Flexport باشید، به این سوال باید پاسخ دهید. هیچ اطلاعاتی ندارید و تمام چیزی که می‌دانید را از شواهد بدست آوردید. 

با توجه به اطلاعاتی که دریافت کردیم، جداولی با فیلدهای زیر در نظر دارم:

Customers: first_name, last_name, email, address (for deliveries to their location)
Packages: weight, content
Transportation: <package_primary_key>, Port, time

اما کلید اصلی را فراموش کردیم. قبل از اینکه ادامه را بخوانید چند لحظه برای کلید اصلی هر کدام از این جداول فکر کنید.

برای جدول Packages، می‌توانیم کلید جانشین PackageID را برای هر بسته انتخاب کنیم. من تلاش کردم که همه ویژگی‌های یک بسته، مانند: وزن، حجم،‌ضخامت و … را لیست کنم که می‌توان به آن‌ها یک بسته را توصیف کرد، اما انجام چنین کاری در عمل سخت است، زیرا مردم به چنین چیزهایی اهمیت نمی‌دهند،‌آن‌ها تنها می‌خواهند بسته‌شان از مبدا به مقصد برسد.

بنابراین این موارد باعث می‌شود تا برای هر ID بسته، یک عدد رندوم ایجاد کنیم. این همان چیزی هست که در سایر سرویس‌های حمل و نقل به عنوان ID و یا بارکد میبینید. در دنیای واقعی هیچ معنایی ندارند و تنها هدفشان این است که توسط آن بتوان وضعیت بسته را دنبال کرد.

برای جدول Customers، از کلید CustomerID استفاده می‌کنیم. اینجا هم انتخاب‌های زیادی داشتیم، ‌مثل استفاده از SSN مشتریان. اما شاید مشتریان ما نخواهند SSN خودشان با در اختیار ما بگذارند. پس خودمان یک کلید ایجاد می‌کنیم و لازم نیست مشتریان ما چیزی در مورد این کلید بدانند و آن‌ها را به طور مثال با CustomerNo.4567 و یا مشتری-4567 خطاب می‌کنیم.

نصب و راه‌اندازی دیتابیس PostgreSQL روی کلاستر Kubernetes
نصب دیتابیس PostgreSQL روی کلاستر

برای جدول Transportation، کلید اصلی مرکب ایجاد می‌کنیم. به نحوی که از ProjectID و Port و Time بدست می‌آید و این نکته جالبی خواهد بود که در ادامه بررسی می‌کنیم. اما در این جدول هم می‌توانستیم مانند دو جدول قبلی کلیدی مثل TransportID ایجاد کنیم. اما اینجا جادوی index پنهان است. کلید اصلی به طور خودکار index می‌شود، این یعنی جست‌وجو میان کلید اصلی به مراتب بهتر و موثرتر است.

وقتی در این دیتابیس به دنبال رکوردی بگردید، بیشتر سوال‌ها این است که: “این بسته الان کجاست؟”. به عبارت دیگر PackageID را دارید، حالا Port و Time فعلی بسته را به من تحویل دهید. در این حالت اگر PackageID بخشی از کلید اصلی نبود ما به index بیشتری نیاز داشتیم.

تعریف جداول در MySQL

CREATE TABLE customers
( customerID  INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  last_name   VARCHAR(30) NOT NULL,
  first_name  VARCHAR(25) NOT NULL,
  email		  VARCHAR(50) NOT NULL,
  address     VARCHAR(300)
);
CREATE TABLE packages
( packageID  INT(15) NOT NULL AUTO_INCREMENT,
  weight     DECIMAL (10, 2) NOT NULL,
  content    VARCHAR(50),
  CONSTRAINT packages_pk PRIMARY KEY (packageID)
);
CREATE TABLE transportation
( package 	INT(15) NOT NULL,
  port  	INT(15) NOT NULL,
  time	 	DATE NOT NULL,
  
  PRIMARY KEY (package, port, time),
  FOREIGN KEY package
  	REFERENCES packages(packageID)
	ON DELETE RESTRICT
);
با هاست ابری MySQL لیارا، پایگاه داده‌تان را در کمترین زمان و با بالاترین امنیت راه‌اندازی کنید.
✅ اتصال سریع و آسان به اپلیکیشن‌ها✅ پشتیبان‌گیری خودکار روزانه✅ امنیت مقیاس‌پذیری
خرید و راه‌اندازی دیتابیس MySQL

تعریف جداول در PostgreSQL

CREATE TABLE customers
( customerID  SERIAL NOT NULL PRIMARY KEY,
  last_name   VARCHAR(30) NOT NULL,
  first_name  VARCHAR(25) NOT NULL,
  address     TEXT,
  email		  VARCHAR(50) NOT NULL
);
CREATE TABLE packages
( packageID  SERIAL NOT NULL,
  weight     NUMERIC NOT NULL,
  content    TEXT,
  CONSTRAINT packages_pk PRIMARY KEY (packageID)
);
CREATE TABLE transportation
( package 	INTEGER NOT NULL,
  port  	INT(15) NOT NULL,
  time	 	DATE NOT NULL,
  
  PRIMARY KEY (package, port, time),
  
  FOREIGN KEY package
  	REFERENCES packages(packageID)
	ON DELETE RESTRICT
);
با هاست ابری PostgreSQL لیارا، پایگاه داده‌تان را در محیطی امن، مقیاس‌پذیر و همیشه دردسترس راه‌اندازی کنید.
✅ اتصال سریع و آسان به اپلیکیشن‌ها✅ پشتیبان‌گیری خودکار روزانه✅ امنیت، مقیاس‌پذیری و عملکرد عالی
خرید و راه‌اندازی دیتابیسPostgreSQL

جمع بندی

همان‌طور که دیدیم، انتخاب کلید اصلی تنها به یکتا بودن وابسته نیست، بلکه باید به پایداری، وجود دائمی و کاربرد عملی آن هم فکر کنیم. چه از شماره پاسپورت استفاده کنیم، چه از یک شناسه ساختگی مانند userID، مهم این است که این کلید باید تا پایان عمر رکورد بدون تغییر باقی بماند و همواره موجود باشد. در مواردی که چنین فیلدی وجود ندارد، ساختن یک کلید جانشین بهترین راهکار است.

در پروژه‌های واقعی، مثل مدیریت بسته‌ها یا کاربران، باید با نگاهی منطقی و آینده‌نگرانه کلید اصلی را انتخاب کنیم؛ کلیدی که نه فقط امروز، بلکه در سال‌های آینده هم قابل اتکا باشد.

منبع: https://www.freecodecamp.org/news/primary-key-sql-tutorial-how-to-define-a-primary-key-in-a-database

به اشتراک بگذارید