CodeCrafters
775 subscribers
90 photos
50 videos
41 files
170 links
Download Telegram
رازهای مخفی تراکنش‌های پایگاه داده: هرچی توی تراکنش هست، همونجا میمونه! (Transaction Scope)

تصور کن یه صندوق داری داری که توش کلی کارای عجیب غریب میشه، ولی هیچکس اجازه نداره سرک بکشه تا وقتی کار تموم نشده! همینه داستان تراکنش‌های پایگاه داده.

فرض کن داری تو دوتا کامپیوتر جدا جدا با یه پایگاه داده کار می‌کنی. کامپیوتر اول یه سری دستورات میده، مثلاً یه اطلاعاتی رو عوض می‌کنه یا یه چیزی اضافه می‌کنه، ولی هنوز کارش تموم نشده. حالا کامپیوتر دوم بخواد همون اطلاعات رو ببینه، چی میشه؟ خب، تا وقتی که کارِ اون یکی کامپیوتر تموم نشده و همه چی تایید نشده، کامپیوتر دوم چیزی نمیبینه!

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

پس یادت باشه، تراکنش‌ها مثل یه سری کارای مخفی تو صندوق می‌مونن تا همه چی جمع و جور بشه. هیچکس زودتر از موعد حق نداره سرک بکشه!

#postgresql
@Code_Crafters
2👍1
تراکنش ها در دنیای واقعی

تراکنش‌ها در دنیای واقعی خیلی پیچیده‌تر از مثال‌های ساده‌ای هستند که دیدیم. مثلاً، فرض کن می‌خوایم یه کارمند جدید در شرکتمون اضافه کنیم. این دستورات ساده هستند و به راحتی اجرا می‌شن. ولی اگه در اجرای یکی از این دستورات خطا رخ بده، تمام تغییراتی که انجام شده‌اند، از بین می‌رن:
BEGIN; 
INSERT INTO employees (first_name, last_name, start_date, salary, job_title, manager_id, department_id) VALUES ('Chris', 'Winslett', current_date, 1, 'Jr Director of the Highwire', 2, 2);
INSERT INTO dependents (first_name, last_name, employee_id) VALUES ('oldest', 'kid', (SELECT employee_id FROM employees WHERE first_name = 'Chris' AND last_name = 'Winslett'));
INSERT INTO dependents (first_name, last_name, employee_id) VALUES ('youngest', 'kid', (SELECT employee_id FROM employees WHERE first_name = 'Chris' AND last_name = 'Winslett'));
COMMIT;




اگه دوباره همون کد بالا رو اجرا کنید، بازم با خطا مواجه می‌شید. دلیلش اینه که دوتا مقدار برای employee_id برمی‌گرده. همچنین، کارمند تکراری هم ایجاد نمی‌شه.

وای! چقدر تراکنش‌ها عالین!

حالا بیایید یه کاری کنیم که ببینیم چطوری تراکنش‌ها با خطا مواجه می‌شن.

اول، سعی می‌کنیم مقدار null رو برای فیلد first_name در دستور دوم قرار بدیم. این فیلد توی جدول اجباریه، پس تراکنش با شکست مواجه می‌شه.

بعد، حقوق (salary) رو حذف می‌کنیم. این کار باعث لغو تراکنش قبل از تاییدش می‌شه.

BEGIN;   
INSERT INTO employees (first_name, last_name, start_date, salary, job_title, manager_id, department_id) VALUES ('Bob', 'Young', current_date, 1, 'Jr Director of the Highwire', 2, 2);
INSERT INTO dependents (first_name, last_name, employee_id) VALUES ('oldest', 'kid', (SELECT employee_id FROM employees WHERE first_name = 'Bob' AND last_name = 'Young'));
INSERT INTO dependents (first_name, last_name, employee_id) VALUES (null, 'kid', (SELECT employee_id FROM employees WHERE first_name = 'Bob' AND last_name = 'Young'));
COMMIT;


حواست باشه! اجرای کدی که دیدی، با خطا مواجه شده و به عقب برگشته. یعنی تغییراتی که قرار بود اعمال بشه، ذخیره نشده. نگران نباش، اینجوری اطلاعاتت سالم می‌مونه. برای اطمینان بیشتر، می‌تونی یه سرچ بزنی و ببینی که اسم "Bob Young" توی لیست کارمندا نیست. خیالت راحت!
SELECT *  FROM employees  WHERE  first_name = 'Bob' AND last_name = 'Young';




دلیل این امر این است که تراکنش به طور کامل انجام نشد. این یک حالت "همه یا هیچ" است.

#postgresql
@Code_Crafters
2
تغییرات ساختار در تراکنش ها

شاید تعجب کنید، اما PostgreSQL اونقدر باحال هست که هیچ تغییری توی ساختار پایگاه داده رو ثبت نمی‌کنه تا زمانی که کل تراکنش با موفقیت انجام بشه! این ویژگی توی دنیای پایگاه‌های داده خیلی خاصه و خیالمون رو راحت می‌کنه.

بذارید با یه مثال براتون توضیح بدم. فرض کنید می‌خوایم یه ستون جدید به اسم "middle_name" به جدول "employees" اضافه کنیم. برای این کار، از دستورات زیر استفاده می‌کنیم:
BEGIN;
ALTER TABLE employees ADD COLUMN middle_name VARCHAR(50) DEFAULT NULL;
COMMIT;


دستور "BEGIN" شروع تراکنش رو مشخص می‌کنه و دستور "COMMIT" هم پایان تراکنش رو نشون می‌ده. هر تغییری که بین این دو دستور انجام بشه، تا زمانی که دستور "COMMIT" اجرا نشه، ثبت نمی‌شه.

حالا اگه از دستور \d employees استفاده کنیم، می‌بینیم که ستون "middle_name" به جدول اضافه شده.

اما اگه یه تغییر پیچیده‌تر بخوایم انجام بدیم و یه اشتباه کوچولو توش داشته باشیم، چی می‌شه؟ مثلاً فرض کنید می‌خوایم چند تا ستون جدید برای آدرس به جدول اضافه کنیم، اما یادمون بره که برای ستون "postal_code" یه مقدار پیش‌فرض تعیین کنیم. دستورات زیر رو ببینید:
BEGIN;
ALTER TABLE employees ADD COLUMN address_line_1 VARCHAR(50) DEFAULT NULL;
ALTER TABLE employees ADD COLUMN address_line_2 VARCHAR(50) DEFAULT NULL;
ALTER TABLE employees ADD COLUMN city VARCHAR(50) DEFAULT NULL;
ALTER TABLE employees ADD COLUMN province VARCHAR(50) DEFAULT NULL;
ALTER TABLE employees ADD COLUMN postal_code VARCHAR(50) NOT NULL;
COMMIT;


به خاطر اینکه کل این تغییرات داخل یه تراکنش قرار گرفتن، و چون برای ستون "postal_code" مقدار پیش‌فرض تعیین نکردیم، هیچ کدوم از تغییرات ثبت نمی‌شن! یعنی اگه دوباره از دستور \d employees استفاده کنیم، می‌بینیم که ستون‌های آدرس اضافه نشدن.

به این ویژگی فوق‌العاده می‌گن "Transactional DDL". توی پایگاه‌های داده دیگه که این ویژگی رو ندارن، ممکنه تغییرات نصفه و نیمه انجام بشن و همه چیز بهم بریزه. اما توی PostgreSQL، یا همه تغییرات با موفقیت انجام می‌شن، یا هیچ تغییری ثبت نمی‌شه.

#postgresql
@Code_Crafters
2
تراکنش‌های پیشرفته: نقطه‌ی نجات (SAVEPOINT)

یه ویژگی توپ دیگه از Postgres می‌خوام بهتون معرفی کنم که کار با تراکنش‌ها رو توی شرایط پیچیده خیلی راحت‌تر می‌کنه. اسمش "نقطه‌ی نجات" یا SAVEPOINT هست.

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

بذار یه مثال بزنم. فرض کنید می‌خوایم یه کارمند جدید به اسم Bob Young اضافه کنیم، بهش چندتا وابسته اضافه کنیم و بعد تراکنش رو تموم کنیم. ولی ممکنه یه جا تو کار اشتباهی پیش بیاد. برای همین از SAVEPOINT استفاده می‌کنیم:
BEGIN;

INSERT INTO employees (first_name, last_name, start_date, salary, job_title, manager_id, department_id) VALUES ('Bob', 'Young', current_date, 1, 'Jr Director of the Highwire', 2, 2);

SAVEPOINT saved_employee; // این نقطه‌ی نجاته!

INSERT INTO dependents (first_name, last_name, employee_id) VALUES ('oldest', 'kid', (SELECT employee_id FROM employees WHERE first_name = 'Bob' AND last_name = 'Young'));

INSERT INTO dependents (first_name, last_name, employee_id) VALUES (null, 'kid', (SELECT employee_id FROM employees WHERE first_name = 'Bob' AND last_name = 'Young'));

ROLLBACK TO SAVEPOINT saved_employee; // اگه یه مشکلی پیش بیاد، به نقطه‌ی نجات برمی‌گردیم!

COMMIT;


حالا اگه اسم Bob Young رو توی کارمندها Search کنیم، پیداش می‌کنیم، ولی وابسته‌هایش رو نمی‌بینیم. چرا؟ چون وقتی توی اضافه کردن وابسته‌ها یه خطایی پیش اومده، تراکنش رو به نقطه‌ی نجات برگردوندیم و فقط اضافه‌کردن Bob Young انجام شده.

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

#postgresql
@Code_Crafters
3👍1
محاصره در تراکنش ها

یه چیزی هست که شاید خیلی‌هاتون متوجهش نشده باشید. اونم اینه که توی PostgreSQL، حتی ساده‌ترین دستورات هم توی یه تراکنش انجام می‌شن! عجیبه نه؟

شاید بگید "خب چطور می‌شه فهمید؟ ما که تراکنشی شروع نکردیم!". ولی یه خورده صبر کنید... می‌تونیم یه دستوری اجرا کنیم که برامون نشون بده الان داخل کدوم تراکنشیم. بفرما:

SELECT txid_current();


حالا چی شد؟ یه عددی بهتون نشون داد، درسته؟ ولی ما که چیزی شروع نکردیم! چون اون عددی که دیدید، شناسه‌ی تراکنشیه که همین الان توش هستید.

حالا بازم همون دستور رو اجرا کنید. چی می‌بینید؟ اون عدد، یه واحد زیادتر شده! آره، این یعنی حتی همین یه دستور کوچیک، یه تراکنش جدید برا خودش باز کرده.

شاید بپرسید چرا انقدر ریزه‌کاری؟ خب، اینجوری PostgreSQL، خیالش راحته که هر تغییری که انجام می‌شه، یا کاملاً انجام می‌شه، یا اصلاً انجام نمی‌شه. اگه توی یه دستور مشکلی پیش بیاد، کل تراکنش باطل می‌شه و هیچ تغییری اعمال نمی‌شه.

پس یادتون باشه، توی PostgreSQL، همیشه تو یه تراکنش هستید، چه بخواهید، چه نخواهید! این یه جور مراقبت اضافه‌ست که داده‌هاتون رو سالم نگه می‌داره.

#postgresql
@Code_Crafters
👍52
پارتیشن‌بندی | Partitioning

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

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

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

پس پارتیشن‌بندی یه راه بی‌نظیره برای اینکه هم انبار اطلاعاتی منظمی داشته باشی، هم هزینه نگهداری رو مدیریت کنی. دیگه لازم نیست نگران انبار شلوغ و هزینه‌های اضافی باشی!

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
2
سرعتِ جت با پارتیشن‌بندی: وقتی انبارت مرتب باشه، پیدا کردن وسایل هم سریع‌تره! 🚀

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

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

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

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
2
انبار داده‌هات رو جورچین کن: با پارتیشن‌بندی‌های مختلف!

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

چیدمان بر اساس بازه (Range): این محبوب‌ترین مدل برای دسته‌های زمانی یا داده‌های عددی مثل سال، ماه، روزه. مثلا می‌تونی اطلاعات فروش سال ۲۰۲۳ رو تو یه قفسه، سال ۲۰۲۴ رو تو یه قفسه دیگه بذاری. پیدا کردن اطلاعات یه سال خاص سریع و آسون می‌شه.

چیدمان بر اساس لیست (List): اگه داده‌هات یه دسته‌بندی مشخص دارن، مثل موقعیت جغرافیایی یا دسته‌های محصول، می‌تونی از این مدل استفاده کنی. مثلا اطلاعات مشتریای تهران رو تو یه قفسه، مشتریای مشهد رو تو یه قفسه دیگه بذاری. جستجو بر اساس دسته‌های خاص به راحتی انجام می‌شه.

چیدمان بر اساس هش (Hash): وقتی دسته‌بندی مشخصی برای داده‌هات نداری، می‌تونی از این مدل استفاده کنی. یه کد هش به هر تیکه اطلاعات اختصاص داده می‌شه و اونو تو قفسه مربوطه می‌ذاره. شبیه یه انبار با برچسب‌های مخفیه!

چیدمان ترکیبی (Composite): اگه دلت می‌خواد از ترکیب مدل‌های مختلف استفاده کنی، این گزینه ایده‌آله. مثلا می‌تونی داده‌های فروش رو هم بر اساس سال (بازه) و هم بر اساس نوع محصول (لیست) دسته بندی کنی. یه انبار مرتب و تفکیک‌شده‌ی دوبل!

این فقط یه نگاه کلی به مدل‌های مختلف پارتیشن‌بندی بود. حالا می‌تونی انتخاب کنی که کدوم مدل برای انبار داده‌هایت بهتره و یه دیتابیس منظم و دسترسی‌پذیر بسازی!

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍1
بیا یه انبار داده‌های باحال بسازیم: مثال پارتیشن‌بندی با PostgreSQL

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

اول یه نگاهی به انبارمون بندازیم:
SELECT * FROM thermostat LIMIT 10;


این دستور ۱۰ تا ردیف اول از جداول thermostat رو نشون میده. هر ردیف شامل تاریخ، شناسه‌ی ترموستات، دمای فعلی و وضعیتش هست. حالا می‌تونیم این انبار رو با پارتیشن‌بندی مرتب‌تر و کارآمدتر کنیم. تو قسمت بعدی قراره ببینیم چطور میشه این کار رو انجام داد!

آماده‌ای بریم سراغ جادوی پارتیشن‌بندی با PostgreSQL؟ ⚡️

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1
ساخت قفسه‌های دیجیتالی: ایجاد جدول پارتیشن‌بندی‌شده

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

دستور زیر رو بزن تا جدول جدید iot_thermostat ساخته بشه:
CREATE TABLE iot_thermostat (
thetime timestamptz,
sensor_id int,
current_temperature numeric (3,1),
thermostat_status text
) PARTITION BY RANGE (thetime);


اینجا به PostgreSQL می‌گیم که جدول iot_thermostat رو با پارتیشن‌بندی بر اساس بازه‌های زمانی (RANGE (thetime)) درست کنه. یعنی قراره اطلاعات ترموستات‌ها رو بر اساس تاریخشون توی قفسه‌های جداگانه بچینیم.

یادت باشه که واسه پیدا کردن سریع‌تر وسایل توی انبار، لازمه برچسب‌های راهنما داشته باشیم. برای این کار از ایندکس‌ها استفاده می‌کنیم. دستور زیر یه ایندکس روی فیلد thetime می‌سازه:

CREATE INDEX ON iot_thermostat(thetime);


اینجوری PostgreSQL می‌تونه خیلی سریع‌تر اطلاعات رو بر اساس تاریخ پیدا کنه. دیگه لازم نیست کل انبار رو زیر و رو کنه!

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

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍2
برچسب‌های روی قفسه‌ها: ایجاد پارتیشن‌های جداگانه

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

دستور زیر قفسه‌هایی برای تاریخ‌های ۲۳ جولای تا ۴ آگوست می‌سازه:

SQL 
CREATE TABLE iot_thermostat07232022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-23 00:00:000') TO ('2022-07-24 00:00:000');
CREATE TABLE iot_thermostat07242022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-24 00:00:000') TO ('2022-07-25 00:00:000');
CREATE TABLE iot_thermostat07252022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-25 00:00:000') TO ('2022-07-26 00:00:000');
CREATE TABLE iot_thermostat07262022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-26 00:00:000') TO ('2022-07-27 00:00:000');
CREATE TABLE iot_thermostat07272022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-27 00:00:000') TO ('2022-07-28 00:00:000');
CREATE TABLE iot_thermostat07282022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-28 00:00:000') TO ('2022-07-29 00:00:000');
CREATE TABLE iot_thermostat07292022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-29 00:00:000') TO ('2022-07-30 00:00:000');
CREATE TABLE iot_thermostat07302022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-30 00:00:000') TO ('2022-07-31 00:00:000');
CREATE TABLE iot_thermosta07312022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-31 00:00:000') TO ('2022-08-01 00:00:000');
CREATE TABLE iot_thermostat08012022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-08-01 00:00:000') TO ('2022-08-02 00:00:000');
CREATE TABLE iot_thermostat08022022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-08-02 00:00:000') TO ('2022-08-03 00:00:000');
CREATE TABLE iot_thermostat08032022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-08-03 00:00:000') TO ('2022-08-04 00:00:000');


یعنی از این به بعد، هر اطلاعاتی که مربوط به تاریخ ۲۳ جولای باشه، مستقیم میره توی قفسه iot_thermostat07232022 و با اطلاعات روزهای دیگه قاطی نمیشه. اینجوری هم انبارت مرتب میمونه، هم پیدا کردن وسایل راحت‌تر میشه.

حالا اگه بخوای اطلاعات یه روز خاص رو ببینی، فقط کافیه به قفسه مربوط به اون روز سر بزنی؛ نیازی نیست کل انبار رو بگردی. این یعنی سرعتِ جت در جستجو و دسترسی به داده‌ها!

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1
چیدن وسایل توی قفسه‌ها: وارد کردن اطلاعات به پارتیشن‌ها

خب، قفسه‌ها آماده‌ان، برچسب‌ها خوردن، حالا وقتشه وسایل رو توشون بچینیم! اینجا با یه دستور ساده، اطلاعات رو از جدول اصلی thermostat به جدول پارتیشن‌بندی‌شده iot_thermostat منتقل می‌کنیم:
INSERT INTO iot_thermostat SELECT * FROM thermostat;

نگران نباش، لازم نیست به PostgreSQL بگی کدوم اطلاعات باید کجا بره. خودش حواسش هست و هر تیکه اطلاعات رو بر اساس تاریخش، توی قفسه مناسبش میذاره. مثل یه ربات قفسه‌چین حرفه‌ای!🤖

برای اینکه مطمئن بشی همه چی درست انجام شده، می‌تونی یه نگاهی به یکی از قفسه‌ها بندازی:
SELECT * FROM iot_thermostat07242022 LIMIT 10;

این دستور ۱۰ تا ردیف اول از قفسه‌ی ۲۴ جولای رو نشون میده. اگه همه چی مرتب باشه، فقط اطلاعات مربوط به همون روز رو باید ببینی.

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

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍2
انبار مرتب، انبار بی‌دردسر: چرخش پارتیشن‌ها

حالا فرض کن دیگه به اطلاعات خیلی قدیمی نیاز نداری و فقط داده‌های اخیر مهم هستن. مثلا می‌خوای اطلاعات ۲۳ جولای رو تو یه جای دیگه آرشیو کنی و از انبار اصلی حذف کنی. اینجا یه ترفند جادویی به اسم چرخش پارتیشن به کار میاد!

با دستور زیر، قفسه مربوط به ۲۳ جولای (iot_thermostat07232022) رو از انبار اصلی جدا می‌کنیم:
ALTER TABLE iot_thermostat DETACH PARTITION iot_thermostat07232022;

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

البته قرار نیست انبار خالی بمونه! باید یه قفسه جدید هم برای اطلاعات جدید بسازیم. دستور زیر یه قفسه با برچسب iot_thermostat0842022 ایجاد می‌کنه که اطلاعات ۴ و ۵ آگوست رو توش جا می‌ده:
CREATE TABLE iot_thermostat0842022 PARTITION OF iot_thermostat
FOR VALUES FROM ('2022-08-04 00:00:000') TO ('2022-08-05 00:00:000');


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

اگه قراره این چرخش رو هر روز انجام بدی، می‌تونی از یه ابزار به اسم cron job استفاده کنی تا همه چی به صورت خودکار و بدون زحمت انجام بشه. دیگه لازم نیست خودت قفسه‌ها رو جابه‌جا کنی!

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

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍1
نکته مهم در مورد کدهای ارائه شده در پست های قبلی:

اگر می‌خواهید کدهای مربوط به تراکنش‌ها و پارتیشن‌بندی را امتحان کنید، لازم نیست PostgreSQL را نصب کنید!

سایت CrunchyData (https://www.crunchydata.com/) که منبع اصلی مقاله ترجمه شده در پست های قبلی بود، یک ترمینال PostgreSQL تعاملی در سمت راست صفحه خود ارائه می‌دهد که می‌توانید از آن برای تست کدها بدون نیاز به نصب هیچ نرم‌افزاری استفاده کنید.

لینک‌های مربوط به ترمینال PostgreSQL:

تراکنش‌ها:
https://www.crunchydata.com/developers/playground/transactions


پارتیشن‌بندی:
https://www.crunchydata.com/developers/playground/partitioning


👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍2
بکاپ گرفتن از دیتابیس پستگرس و ارسال آن به یک گروه خصوصی و تنظیم زمان بندی جهت اجرای مداوم آن در لینوکس


سناریو از چه قرار خواهد بود
ما یک دیتابیس پستگرس داریم و روی داکر بصورت کانتینر در سرور اجرا شده و میخوایم ازش بکاپ گرفته و در تلگرام اون رو داشته باشیم

ابتدا تلگرام رو آماده میکنیم
مراحل زیر رو گام بگام باهم پیش میریم

مرحله اول:
ابتدا یک بات تلگرامی میسازیم
به بات پدر @BotFather رفته  و استارت رو میزنیم
درخواست newbot/ رو میزنیم
از ما یک اسم میخواد که اسمش رو میزاریم backup
از ما یوزرنیم میخواد که با bot اتمام شود که ترکیبی مینویسیم bakup<projectname>bot

و بعد از اتمام پیغام موفقیت و در آن token bot رو میگیریم و نگه میداریم و این توکن رو با نام BOT_TOKEN میشناسیم
مرحله دوم:
یک گروه خصوصی ساخته و بات بالا رو به همراه کاربرانی که میخواهیم به فایل‌های بکاپ دسترسی داشته باشن رو اضافه میکنیم
به ربات @raw_data_bot رفته استارت رو میزنیم سپس chat رو انتخاب میکنیم و از میان لیست باز شده گروه خصوصی ساخته شده رو بهش میدیم و chat id رو ازش میگیریم و نگه میداریم و با نام CHAT_ID اون رو میشناسیم


اماده سازی سرور
مراحل رو گام بگام پیش میریم

مرحله اول:
با دستور docker ps نام کانتینر پستگرس رو نگه میداریم و با نام CONTAINER_NAME میشناسیم

نام دیتابیس ما در پستگرس رو هم با DB_NAME میشناسیم

اگر پسورد شما با نام دیتابیس متفاوت هست اون رو هم نگه دارید و اگه پورت پیش فرض رو هم تغییر داده‌اید اون رو هم لازم دارید(ما تصور میکنیم که پورت پیش فرض و پسورد دیتابیس با نام اون یکسان است)

مرحله دوم:
ساخت یک دایرکتوری برای بکاپ‌ها
در یک مسیر دلخواه در سرور یک دایرکتوری با اسم backups میسازیم 
mkdir backups
chmod 777 backups
cd backups

سپس مسیر آنرا با دستور زیر خواهیم گرفت
pwd
این مسیر رو نگه میداریم و با نام PATH میشناسیم


مرحله سوم:
ساخت یک فایل حاوی کدهای بش اسکریپت
یک فایل با نام backup.sh ساخته و کدهای زیر رو در اون قرار میدیم
sudo nano backup.sh
کدهای زیر رو در اون بزارید
#!/bin/bash

docker exec -t <CONTAINER_NAME> pg_dumpall -c -U <DB_NAME> > <PATH> backup_$(date +%Y%m%d-%H%M).sql


curl -s -X POST -F chat_id=<CHAT_ID> -F caption=<CAPTION> -F document=@$(ls -t <PATH> backup_*.sql | head -1) https://api.telegram.org/bot<BOT_TOKEN>/sendDocument


find <PATH> -type f -name "backup_*.sql" -mtime +7 -exec rm {} \;

توضیحات کد
در خط اول به کانتینر وصل شده و فایل بکاپ رو گرفته و در دایرکتوری backups ذخیره میکنیم درون اسم فایل بکاپ تایم رو هم میگذاریم

در خط دوم فایل بکاپ گرفته رو به تلگرام انتقال میدهیم

در خط سوم هر فایل بکاپی که یک هفته از آن گذشته باشه رو حذف میکنیم(بکاپ‌های یک هفته‌ای رو نگه میداریم فقط)
نکته: درون فایل بش اسکریپتی مقادیری رو که گفتیم با این نام میشناسیم رو با مقدار مطابق خودشون در این فایل جابجا کرده و فایل رو ذخیره میکنیم در مقدار <CAPTION> متن دلخواه خود را بزارید


بعد از اتمام یکبار با دستور زیر فایل بش اسکریپت رو اجرا کرده و نتیجه کار رو میبینیم

sudo ./backup.sh



زمان بندی کردن بکاپ گیری جهت اجرا شدن در بازه‌های زمانی متداول

اینکار رو با استفاده از کرون‌جاب‌های لینوکس انجام میدهیم

دستور crontab -e رو میزنیم

سپس یک ادیتور انتخاب میکنیم

و مقدار زیر رو به فایل اصافه کرده و ذخیره میکنم
0 24 * * * <PATH>backup.sh
هر روز ساعت دوازده شب یک فایل بکاپ براتون ارسال خواهد شد در تلگرام


#postgresql

@code_crafters
👍8
باینری ها در PostgreSQL: ذخیره سازی اطلاعات خام

تصور کنید می‌خواهید عکسی از گربه‌تان را در PostgreSQL ذخیره کنید. چطور می‌توانید این کار را انجام دهید؟

پایگاه داده PostgreSQL نوع داده‌ای به نام bytea را ارائه می‌دهد که برای ذخیره اطلاعات باینری مانند تصاویر، فایل‌های صوتی و ویدئوها ایده‌آل است.

تفاوت باینری و رشته‌های کاراکتری:

* رشته‌های باینری مانند "بایت‌های خام" هستند و می‌توانند هر نوع داده‌ای را ذخیره کنند، از جمله صفر و کاراکترهای غیرقابل چاپ.
* رشته‌های کاراکتری برای ذخیره متن مناسب هستند و محدودیت‌هایی در مورد کاراکترهای مجاز دارند.

فرمت‌های ذخیره سازی:

هگزادسیمال: هر بایت به عنوان دو رقم شانزده‌گانی نمایش داده می‌شود (مثلاً "00" برای بایت صفر). این فرمت خوانایی بیشتری دارد.
نوع Escape: برخی از بایت‌ها با کاراکترهای خاص علامت‌گذاری می‌شوند. این فرمت قدیمی‌تر است و کاربرد کمتری دارد.

کاربردها:

۱.ذخیره تصاویر، فایل‌های صوتی و ویدئوها
۲.ذخیره داده‌های باینری مانند کدهای برنامه
۳.ذخیره اطلاعات رمزنگاری شده

مثال:

فرض کنید می‌خواهید تصویر گربه‌تان را با نام cat.jpg در پایگاه داده ذخیره کنید:

INSERT INTO photos (name, data)
VALUES ('cat.jpg', BYTEA('\xFF\xD8\xFF\xE0'));


نکات:

پایگاه داده PostgreSQL از نوع داده BLOB (Binary Large Object) نیز برای ذخیره داده‌های باینری پشتیبانی می‌کند. فرمت ورودی BLOB با bytea متفاوت است، اما توابع و عملگرهای مشابهی دارند.
می‌توانید از توابع و عملگرهای مختلفی برای کار با داده‌های bytea استفاده کنید، مانند LENGTH(), SUBSTRING() و COMPARE().

نتیجه:

نوع داده bytea یک ابزار قدرتمند برای ذخیره و مدیریت داده‌های باینری در PostgreSQL است. با استفاده از این نوع داده، می‌توانید انواع مختلف اطلاعات را به طور کارآمد و ایمن ذخیره کنید.

#PostgreSQL
@Code_Crafters
5👍2🔥2
ذخیره سازی اطلاعات خام ولی در حجم بالا با Blob در PostgreSQL

در پایگاه داده PostgreSQL نوع داده‌ای به نام bytea را ارائه می‌دهد که برای ذخیره اطلاعات باینری مانند تصاویر، فایل‌های صوتی و ویدئوها ایده‌آل است. اما گاهی اوقات با داده‌های باینری خیلی بزرگتر از حد معمول سروکار داریم. در اینجاست که مفهوم BLOB یا "Binary Large Object" به کمک ما می‌آید.

تعریف BLOB چیست؟

در واقع BLOB یک نوع داده در PostgreSQL است که برای ذخیره داده‌های باینری بسیار بزرگ مانند:

۱. فایل‌های چند گیگابایتی
۲. مجموعه داده‌های علمی
۳. تصاویر با وضوح بالا
۴. فایل‌های ویدئویی با کیفیت بالا

استفاده می‌شود.

مزایای استفاده از BLOB:

* ذخیره سازی داده‌های حجیم: BLOB ها می‌توانند داده‌هایی با حجم تا 1 ترابایت را ذخیره کنند.
* کارایی: BLOB ها برای ذخیره سازی داده‌های باینری بهینه شده‌اند و می‌توانند عملکرد بهتری نسبت به ذخیره سازی داده‌های باینری در قالب رشته‌های متنی ارائه دهند.
* انعطاف پذیری: BLOB ها می‌توانند برای ذخیره هر نوع داده باینری، صرف نظر از نوع و فرمت آن، استفاده شوند.

نحوه استفاده از BLOB:

برای استفاده از BLOB در PostgreSQL، باید مراحل زیر را انجام دهید:

1. نوع داده BLOB را در جدول خود تعریف کنید:
CREATE TABLE my_table (
id INT PRIMARY KEY,
data BYTEA
);

2. با استفاده از دستور INSERT، داده‌های BLOB را در جدول ذخیره کنید:
INSERT INTO my_table (id, data)
VALUES (1, lo_import('image.jpg'));

3. با استفاده از دستور SELECT، داده‌های BLOB را از جدول بازیابی کنید:
SELECT data FROM my_table WHERE id = 1;

نکات مهم:

برای ذخیره و بازیابی BLOB ها، باید از توابع lo_import و lo_export استفاده کنید.
پایگاه داده PostgreSQL ابزارهای مختلفی برای مدیریت BLOB ها ارائه می‌دهد، مانند توابع و عملگرهای خاص.
برای اطلاعات بیشتر در مورد BLOB ها، می‌توانید به مستندات PostgreSQL مراجعه کنید.

مثال:

فرض کنید می‌خواهید یک ویدیو با حجم 2 گیگابایت را در PostgreSQL ذخیره کنید. می‌توانید مراحل زیر را انجام دهید:

1. نوع داده BLOB را در جدول خود تعریف کنید:
CREATE TABLE videos (
id INT PRIMARY KEY,
title VARCHAR(255),
data BYTEA
);

2. با استفاده از دستور INSERT، ویدیو را در جدول ذخیره کنید:
INSERT INTO videos (id, title, data)
VALUES (1, 'My Video', lo_import('video.mp4'));

3. با استفاده از دستور SELECT، ویدیو را از جدول بازیابی کنید:
SELECT data FROM videos WHERE id = 1;

با استفاده از BLOB ها، می‌توانید هر نوع داده باینری را در PostgreSQL ذخیره کنید و به آنها دسترسی داشته باشید. این امر PostgreSQL را به یک راه حل قدرتمند برای ذخیره سازی و مدیریت داده‌های باینری تبدیل می‌کند.

در ادامه، چند نمونه دیگر از کاربردهای BLOB در PostgreSQL آورده شده است:

۱. ذخیره سازی اسناد و مدارک
۲. ذخیره سازی تصاویر و ویدیوها
۳. ذخیره سازی فایل‌های صوتی
۴. ذخیره سازی پایگاه داده‌های NoSQL
۵. ذخیره سازی داده‌های رمزنگاری شده

جمع بندی:

در واقع BLOB ها یک ابزار قدرتمند برای ذخیره سازی داده‌های باینری در PostgreSQL هستند. با استفاده از BLOB ها، می‌توانید داده‌های حجیم را به طور کارآمد و ایمن ذخیره کنید.

#PostgreSQL
@Code_Crafters
🔥62
خب در ادامه پست های استفاده از ایندکس در جداول دیتابیس قرار در این پست با Multi-Column Indexes اشنا بشیم/

ایندکس‌های چندستونی (Multi-Column Indexes) برای بهبود کارایی جستجو در جداولی که به طور مکرر از چندین ستون در کوئری‌های خود استفاده می‌کنند، بسیار مفید هستند. این نوع ایندکس‌ها بر روی بیش از یک ستون از جدول ایجاد می‌شوند و می‌توانند به طور همزمان ترتیب چند ستون را برای بهبود سرعت جستجو حفظ کنند.

ویژگی‌های ایندکس‌های چندستونی
1. ترتیب ستون‌ها:
   - ترتیب ستون‌هایی که در ایندکس تعریف می‌شوند بسیار مهم است.
   - ایندکس ابتدا بر اساس ستون اول مرتب می‌شود و سپس در داخل هر مقدار ستون اول، بر اساس ستون دوم و به همین ترتیب ادامه می‌یابد.
   - انتخاب ترتیب مناسب ستون‌ها بر اساس الگوهای کوئری معمول، می‌تواند تاثیر زیادی بر کارایی جستجو داشته باشد.

2. بهبود کارایی:
   - ایندکس‌های چندستونی می‌توانند کارایی کوئری‌هایی را که از این ستون‌ها در شرط WHERE، ORDER BY، و GROUP BY استفاده می‌کنند، بهبود بخشند.
   - در کوئری‌هایی که فقط از ستون اول ایندکس استفاده می‌کنند نیز می‌تواند بهبود کارایی ایجاد کند.

3. محدودیت‌ها:
   - ایندکس‌های چندستونی می‌توانند فضای بیشتری را نسبت به ایندکس‌های تک‌ستونی اشغال کنند.
   - به‌روزرسانی‌های جداولی که دارای ایندکس‌های چندستونی هستند می‌توانند زمان‌برتر باشند به دلیل نیاز به بروزرسانی ساختار ایندکس.

مثال‌ها و کد

فرض کنید یک جدول به نام employees داریم که شامل ستون‌های first_name، last_name، و department_id است و می‌خواهیم یک ایندکس چندستونی بر روی ستون‌های last_name و department_id ایجاد کنیم.

ایجاد ایندکس چندستونی
در SQL، ایجاد یک ایندکس چندستونی به شکل زیر است:

CREATE INDEX idx_lastname_department ON employees (last_name, department_id);


این ایندکس ابتدا بر اساس last_name و سپس بر اساس department_id مرتب می‌شود.

استفاده از ایندکس چندستونی در کوئری‌ها

مثال 1: جستجو بر اساس هر دو ستون
SELECT * FROM employees WHERE last_name = 'Doe' AND department_id = 5;

در این کوئری، هر دو ستون last_name و department_id استفاده شده‌اند، بنابراین ایندکس idx_lastname_department به طور کامل بهره‌برداری می‌شود و کارایی جستجو افزایش می‌یابد.

مثال 2: جستجو بر اساس ستون اول
SELECT * FROM employees WHERE last_name = 'Doe';

در این کوئری، تنها ستون last_name استفاده شده است که ستون اول ایندکس است. بنابراین ایندکس هنوز هم می‌تواند کارایی جستجو را بهبود بخشد.

مثال 3: جستجو بر اساس ستون دوم
SELECT * FROM employees WHERE department_id = 5;

در این کوئری، تنها ستون department_id استفاده شده است که ستون دوم ایندکس است. این کوئری نمی‌تواند از ایندکس idx_lastname_department بهره‌برداری کند و به احتمال زیاد از اسکن کامل جدول استفاده خواهد کرد.

به‌روزرسانی و حذف ایندکس
برای حذف یک ایندکس چندستونی:

DROP INDEX idx_lastname_department ON employees;


نکات مهم
1. انتخاب ستون‌ها: ستون‌هایی را انتخاب کنید که در بیشتر کوئری‌ها استفاده می‌شوند و ترتیب آنها را بر اساس بیشترین تاثیر بر کارایی جستجو تعیین کنید.
2. نگهداری و به‌روزرسانی: با افزایش تعداد ایندکس‌ها، عملیات نوشتن (INSERT, UPDATE, DELETE) کندتر می‌شود. به همین دلیل، باید توازن مناسبی بین تعداد ایندکس‌ها و نیازهای جستجو برقرار کرد.
3. تحلیل کارایی: استفاده از ابزارهای تحلیل کارایی (مانند EXPLAIN در SQL) برای بررسی تاثیر ایندکس‌ها بر کوئری‌ها مفید است.

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


#database
#postgresql
👍41
در ادامه پست ها راجب استفاده از ایندکس در دیتابیس, در این پست قراره نحوه استفاده از Multi-Column Indexes ها در جنگو ببینیم. همچنین اگه نمیدونید که Multi-Column Indexe چیه و دقیقا چیکار میکنه, اول این پست رو مطالعه کنید.

1. تعریف مدل با ایندکس چندستونی
فرض کنید یک مدل به نام Employee داریم که شامل فیلدهای first_name، last_name، و department_id است. برای ایجاد ایندکس چندستونی بر روی last_name و department_id، می‌توانید از ویژگی Meta در مدل استفاده کنید.


from django.db import models

class Employee(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
department_id = models.IntegerField()

class Meta:
indexes = [
models.Index(fields=['last_name', 'department_id']),
]

def __str__(self):
return f'{self.first_name} {self.last_name}'

در این کد، یک ایندکس چندستونی بر روی last_name و department_id تعریف شده است.



2. استفاده از ایندکس در کوئری‌ها
پس از ایجاد ایندکس، می‌توانید کوئری‌هایی بنویسید که از این ایندکس بهره‌مند شوند. به عنوان مثال:

مثال 1: جستجو بر اساس هر دو ستون


from .models import Employee

employees = Employee.objects.filter(last_name='Doe', department_id=5)

در این کوئری، هر دو ستون last_name و department_id استفاده شده‌اند، بنابراین ایندکس به طور کامل بهره‌برداری می‌شود و کارایی جستجو افزایش می‌یابد.

مثال 2: جستجو بر اساس ستون اول

employees = Employee.objects.filter(last_name='Doe')

در این کوئری، تنها ستون last_name استفاده شده است که ستون اول ایندکس است. بنابراین ایندکس هنوز هم می‌تواند کارایی جستجو را بهبود بخشد.

مثال 3: جستجو بر اساس ستون دوم

employees = Employee.objects.filter(department_id=5)

در این کوئری، تنها ستون department_id استفاده شده است که ستون دوم ایندکس است. این کوئری نمی‌تواند از ایندکس چندستونی بهره‌برداری کند و به احتمال زیاد از اسکن کامل جدول استفاده خواهد کرد.

3. تحلیل کارایی
برای تحلیل کارایی کوئری‌ها و مشاهده اینکه آیا ایندکس‌ها استفاده می‌شوند یا خیر، می‌توانید از ابزارهایی مانند django-debug-toolbar استفاده کنید که اطلاعات کوئری‌ها و ایندکس‌ها را نمایش می‌دهد.

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

#database
#postgresql


@code_crafters
🔥5
خب سلام دوباره در ادامه مجموعه پست های دیتابیس تو این یکی قراره با معماری Vitess اشنا بشیم و متوجه بشیم یوتوب چگونه 2.49 میلیارد کاربر خودش رو با MySQL هندل میکنه.
توجه این پست بر اساس تحقیق هستش و ممکنه با پیاده‌سازی واقعی فرق داشته باشه.



روزی روزگاری، سه نفر که تو PayPal کار می‌کردن، تصمیم گرفتن یه سایت دوستیابی درست کنن. اما مدل کسب‌وکارشون شکست خورد. برای همین ایده‌شون رو عوض کردن و یه سایت اشتراک‌گذاری ویدئو درست کردن و اسمش رو گذاشتن یوتیوب.

اونا عناوین ویدئوها، توضیحات و اطلاعات کاربران رو تو MySQL ذخیره کردن. وقتی کاربرهای بیشتری به سایت پیوستن، اونا MySQL رو به حالت رهبر-دنبال‌کننده (leader-follower replication topology) تنظیم کردن تا بتونن بهتر مقیاس‌پذیری کنن. اما تکرار در MySQL تک‌نخی (single-threaded) است. بنابراین دنبال‌کننده‌ها نمی‌تونستن در عملیات نوشتن شدید به رهبر برسند و داده‌های جدید رو به‌روز کنن. با این حال، نرخ رشدشون خیلی زیاد بود و به یک میلیارد کاربر رسیدن و به دومین سایت پربازدید در جهان تبدیل شدن.

بنابراین با اضافه کردن یه حافظه نهان (cache) مقیاس‌پذیری کردن و همه رویدادها رو از لاگ باینری MySQL (binary log) بارگذاری کردن. این یعنی تکرار به حافظه وابسته شد و سرعت بیشتری پیدا کرد. اگرچه این کار به طور موقت مشکل مقیاس‌پذیری اونا رو حل کرد، مشکلات جدیدی به وجود اومد.

در اینجا به برخی از اونا اشاره می‌کنم:

1. پارتیشن‌بندی (Sharding):
اولین کاری که باید کرد این که MySQL باید پارتیشن‌بندی بشه تا نیازهای ذخیره‌سازی رو مدیریت کنه. اما بعد از پارتیشن‌بندی، معاملات (transactions) و پیوستن جداول (joins) سخت میشه. بنابراین منطق برنامه (application logic) باید این رو مدیریت کنه. این یعنی منطق برنامه باید بفهمه که کدوم پارتیشن‌ها رو باید پرس‌وجو کنه و این باعث افزایش احتمال زمان خرابی (downtime) میشه.

2. عملکرد (Performance):
و(leader-follower replication topology) باعث میشه که داده‌های قدیمی از دنبال‌کننده‌ها خونده بشه. بنابراین منطق برنامه باید خوندن داده‌ها رو به رهبر هدایت کنه اگر داده‌های جدید لازم باشه. و این نیاز به پیاده‌سازی منطق اضافی داره.

3. حفاظت (Protection):

ریسک اینکه برخی پرس‌وجوها خیلی طول بکشه تا داده‌ها رو برگردونن وجود داره. همچنین تعداد زیادی از اتصالات MySQL به طور همزمان می‌تونه مشکل‌ساز بشه و ممکنه دیتابیس رو از کار بندازه.

اونا می‌خواستن یه لایه انتزاعی روی MySQL برای سادگی و مقیاس‌پذیری ایجاد کنند. بنابراین Vitess رو ساختن. در اینجا نحوه ارائه مقیاس‌پذیری بالا توسط Vitess رو توضیح می‌دم:

1. تعامل با پایگاه داده:(Interacting with Database)
اونا یه سرور جانبی (sidecar server) جلو هر نمونه MySQL نصب کردن و اسمش رو گذاشتند VTTablet.

این سرور جانبی به اونا اجازه می‌داد:
- کنترل سرور MySQL و مدیریت پشتیبان‌گیری از پایگاه داده
- بازنویسی کوئری‌های سنگین با اضافه کردن محدودیت (limit clause)
- کش کردن داده‌های پر دسترس برای جلوگیری از مشکل Thundering Herd

2. مسیریابی کوئری‌ها(Routing SQL Queries):

یه سرور پراکسی بدون حالت (stateless proxy server) برای مسیریابی کوئری‌ها تنظیم کردند و اسمش رو گذاشتند VTGate.

این سرور پراکسی بهشون اجازه می‌داد:
- پیدا کردن VTTablet صحیح برای مسیریابی کوئری بر اساس اسکیما و طرح پارتیشن‌بندی
- پایین نگه داشتن تعداد اتصالات MySQL از طریق تجمیع اتصالات (connection pooling)
- صحبت با لایه کاربردی به پروتکل MySQL
- عمل کردن مانند یه سرور MySQL یکپارچه برای سادگی
- محدود کردن تعداد معاملات در یک زمان برای عملکرد بهتر

همچنین برای مقیاس‌پذیری بیشتر، سرورهای VTGate متعددی راه‌اندازی کردند.

3. اطلاعات حالت:
تصویر چهارم در کامنت ها
یه پایگاه داده توزیع‌شده کلید-مقدار (distributed key-value database) راه‌اندازی کردند تا اطلاعات مربوط به اسکیما، طرح‌های پارتیشن‌بندی و نقش‌ها رو ذخیره کنه.

این پایگاه داده همچنین روابط بین پایگاه‌های داده مثل رهبر و دنبال‌کننده‌ها رو مدیریت می‌کنه.

در ادمه از Zookeeper برای پیاده‌سازی این پایگاه داده کلید-مقدار استفاده کرندند.

علاوه بر این، این داده‌ها رو در VTGate برای عملکرد بهتر کش میکردند.
برای به‌روزرسانی پایگاه داده کلید-مقدار، یه سرور HTTP راه‌اندازی کردند و اسمش رو گذاشتند VTctld. این سرور فهرست کامل سرورها و روابطشون رو می‌گیره و سپس پایگاه داده کلید-مقدار رو به‌روزرسانی می‌کنه.


#database
#postgresql


@code_crafters
🔥8👍1