تصور کنید تنها یک پرسوجو در Prela بتواند جایگزین بیش از ۲۰ خط کد SQL سنتی شود. این زبان جدید که در UCLA RePL توسعه یافته است، منطق بنیادین بازیابی دادهها را از جداول عریض به سیستمی از روابط دوتایی تغییر میدهد.
بسیاری از توسعهدهندگان به پایگاهدادهها بهعنوان مجموعهای از جداول با ستونهای متعدد نگاه میکنند. این ساختار باعث میشود اتصال دادهها (Join) پیچیده و طولانی شود. Prela با به چالش کشیدن این عرف، پیشنهاد میکند که هر جدول باید به جفتهای سادهای از دادهها تجزیه شود.
همانطور که در تحلیلهای پیشین ما درباره بهینهسازی ساختارهای داده اشاره کردیم، سادهسازی لایههای دسترسی به اطلاعات همواره منجر به کاهش خطای انسانی میشود. در Prela، این سادهسازی از طریق مفهومی به نام «دوتاییسازی» رخ میدهد.
مفهوم دوتاییسازی
یک پایگاهداده فیلم را در نظر بگیرید. بهجای یک جدول واحد شامل شناسهها، عناوین و سالها، Prela این دادهها را به سه رابطه دوتایی مجزا تقسیم میکند. به نقل از مستندات پروژه، این فرآیند «تجزیه 6NF» نام دارد. برای مثال، جدولی شامل فیلمهای پدرپدری (شناسه ۶۴۶)، هفت سامورایی (شناسه ۴۷۸) و کازابلانکا (شناسه ۵۸۳) به این شکل تقسیم میشود:
- movie: شناسه را به شماره ردیف متصل میکند (مثلاً
(646, 0), (478, 1), (583, 2)). - title: شماره ردیف را به عنوان فیلم متصل میکند (مثلاً
(0, "The Godfather"), (1, "Seven Samurai"), (2, "Casablanca")). - year: شماره ردیف را به سال تولید متصل میکند (مثلاً
(0, 1972), (1, 1954), (2, 1942)).
در اینجا شماره ردیف در روابط عنوان و سال در ابتدا، اما در رابطه فیلم در انتها قرار میگیرد. این ساختار دقیق است که مکانیسم اصلی زبان، یعنی «ترکیب»، را ممکن میسازد.
مکانیسم ترکیب
قدرت اصلی Prela در ترکیب روابط است. چون روابط دوتایی مانند توابع غیرقطعی عمل میکنند، میتوان آنها را با استفاده از عملگر .select (یا .s) به هم زنجیر کرد.
- رفتار تابعگونه: یک تابع هر ورودی را به یک خروجی منحصربهفرد میبرد. یک رابطه این مفهوم را تعمیم میدهد و یک ورودی را به چندین خروجی مختلف متصل میکند. در پیادهسازی پایتونی این زبان، فراخوانی یک رابطه بهسادگی تبدیل آن به یک دیکشنری و جستوجوی مقدار است. برای مثال، دستور
print(dict(movie)[646], dict(title)[0], dict(year)[0])دادههای مربوط به یک فیلم خاص را استخراج میکند. - زنجیرهسازی: شما میتوانید یک فیلم را به شرکت سازندهاش و سپس آن شرکت را به کشورش متصل کنید، آن هم در یک خط کد روان. ترکیب دو رابطه
rوsباعث میشود مقدارxاز طریقrبهyبرسد و سپسyاز طریقsبه خروجی نهایی تبدیل شود. این فرآیند در لایه پیادهسازی با تبدیلsبه یک دیکشنریdو پیمایش جفتهای(x, y)درrانجام میشود؛ اگرyدرdیافت شود، خروجی(x, d[y])خواهد بود. - حل خودکار: در SQL، اتصال از طریق کلید خارجی معمولاً نیاز به «حل کردن» (Resolving) یک شناسه به یک ردیف دارد. Prela این مرحله را بهطور خودکار درج میکند تا پرسوجوها شبیه زبان طبیعی خوانده شوند:
movie.s(company).s(country). این کار نیاز به تعریف دستی روابط نگاشت شناسه به ردیف مانندid2row(مثلاًRel([(0, 0), (1, 1), (2, 2)])) را از بین میبرد.
مدیریت ویژگیهای متعدد
برای استخراج بیش از یک ستون، Prela از عملگر & استفاده میکند. طبق گزارش تیم توسعه، این عملگر دو رابطه را بر اساس ستون اولشان ادغام کرده و ستونهای دوم را در قالب یک «تاپل» (Tuple) جفت میکند.
در پیادهسازی پایتون، تابع and_(r, s) یک دیکشنری از s ایجاد میکند و برای هر x, y در r که x در s موجود باشد، مقدار (x, (y, d[x])) را برمیگرداند.
برای مثال، ترکیب title & year یک رابطه دوتایی میسازد که ردیف فیلم را بهطور همزمان به عنوان و تاریخ انتشار متصل میکند. این نتیجه همچنان یک رابطه دوتایی باقی میماند و میتوان آن را بدون شکستن جریان منطقی، با عملگرهای دیگر ترکیب کرد. یک پرسوجو مانند movie.select(title & year) هر دو ویژگی را برای تمام فیلمها واکشی میکند.
فیلترها و گزارهها
فیلتر کردن دادهها در Prela از طریق گزارهها و عملگر .where انجام میشود. متد .eq(v) رابطه را فیلتر میکند تا فقط جفتهایی باقی بمانند که ستون دوم آنها با مقدار خاص v برابر است.
وقتی این گزاره به .where پاس داده شود، بهعنوان فیلتری برای رابطه دیگر عمل میکند. تابع .where(r, s) یک گزاره را به فیلتر تبدیل میکند؛ این کار با بررسی اینکه آیا مقدار y در رابطه r در دیکشنری رابطه s وجود دارد یا خیر، صورت میگیرد.
پرسوجویی مانند movie.where(company.s(country).eq("[us]")) دقیقاً به این معناست: «فیلمهایی که کشور شرکت سازندهشان ایالات متحده است».
منطق و CTEها
Prela متغیرهای استاندارد پایتون را به «عبارات جدولی مشترک» (CTE) تبدیل میکند. چون هر زیر-عبارت یک پرسوجوی معتبر است، میتوانید یک فیلتر را به متغیر اختصاص دهید — مثلاً american = company.s(country).eq("[us]") — و از آن در چندین پرسوجوی مختلف استفاده کنید.
علاوه بر این، عملگر & وقتی داخل یک عبارت .where قرار میگیرد، بهعنوان یک «AND» منطقی عمل میکند. این قابلیت به توسعهدهندگان اجازه میدهد چندین شرط را روی هم بچینند، بدون اینکه نیاز به نوشتن دستورات پیچیده JOIN داشته باشند. برای مثال، فیلتر کردن فیلمهایی که هم آمریکایی باشند و هم در سال ۱۹۴۲ منتشر شده باشند، به صورت movie.where(american & year.eq(1942)) نوشته میشود که در این مورد خاص، تنها فیلم کازابلانکا از فیلتر عبور میکند.
مثالهای پرسوجوی پیچیده
بر اساس آموزشهای prela-lang.org، این رویکرد اجازه میدهد پرسوجوهای پیچیده در کسری از فضای مورد نیاز SQL نوشته شوند. برای مثال، یافتن فیلمهای شرکتهای آمریکایی که کلمات کلیدی خاصی در عنوان دارند، به این شکل ساده میشود:
movie.where(company.s(country).eq("[us]") & keyword.eq("character-name-in-title")).select(title & cast.s(person).s(alias).s(text))
این کد فیلمهای مورد نظر را مییابد و عنوان آنها را بههمراه نام مستعار هر بازیگر خروجی میدهد. این مثال قدرت ترکیب عمیق را در زنجیره cast.s(person).s(alias).s(text) نشان میدهد.
این تغییر دیدگاه، بازیابی دادهها را از عملیات مجموعهای به مجموعهای از ترکیبهای تابعی تبدیل میکند و بار ذهنی مدیریت کلیدهای اتصال و نامهای مستعار جداول را از دوش برنامهنویس برمیدارد.
اگرچه نسخه فعلی یک مدل آزمایشی در پایتون است، اما نسخه کامل زبان از گروهبندی، تجمیع و تکنیکهای کامپایل پیشرفته مانند CPS (Continuation-Passing Style) برای حذف هزینههای اضافی (Overhead) ناشی از غیرمستقیم بودن در تجزیه 6NF پشتیبانی میکند. همچنین برای جلوگیری از وضعیتهای فاسد (Corrupted State) در حین توسعه، در آموزشها پیشنهاد شده است که بهجای Jupyter از snip برای اتصال سلولهای کد استفاده شود، زیرا snip کدها را از ابتدا و بهصورت تازه اجرا میکند.
گام بعدی شما
- اگر با SQLهای طولانی دستوپنجه نرم میکنید، منطق «روابط دوتایی» را در پروژههای کوچک خود امتحان کنید.
- برنامه پایتونی ارائه شده توسط تیم UCLA RePL را بررسی کنید تا نسخه آزمایشی خودتان را بسازید.
- مستندات prela-lang.org را برای یادگیری نحوه تبدیل جداول عریض به روابط ساده مطالعه کنید.
اما تأثیر این رویکرد بر سرعت اجرای پرسوجوها در مقیاس میلیونی هنوز یک علامت سؤال است — به تحلیل ما درباره بهینهسازی موتورهای دیتابیس مراجعه کنید.




گفتگو