————————————
میدونیم که SQL یک زبان با پارادایم declarativeـه. تو این پارادایم، چگونگی انجام عملیات توسط برنامه نویس گفته نمیشه. صرفا ویژگیهای نتیجه مطلوب هست که اعلان میشه.
اینجا با این کار نداریم که کارمون چطوری انجام بشه. این که جوابی که ما میخواییم رو با اون ویژگیهایی که اعلان کردیم بگیریم مهمه.
خب اینجا سوالی پیش میاد. چطوری دیتابیس تصمیم میگیره که چطوری به مطلوب ما (داده ها) که در قالب یک کوئری بیان شده پاسخ بده. چطوری طرح اجرای یک کوئری یا Query plan رو برای خودش بسازه؟ اینجاست که پای Query plannerها وسط میاد.
همون طور که گفتیم بالاتر، query plan یا query execution plan، توالی از مراحله برای دستیابی به داده در RDBMSهاست. به عبارت ساده تر، برای این که RDBMSما بدونه چطوری به داده های درخواست شده دسترسی پیدا کنه، نیاز به این داره که بهش گفته بشه چه کار هایی رو به ترتیب انجام بده. به این میگیم query plan. چه کسی این plan رو مشخص میکنه؟ query planner. دقت کنین که این تصمیم مبنی بر اینه که پلن مشخص شده optimal باشه.
Query planner
توی RDBMSهای مختلف اسم های مختلفی داره. PostgreSQLبهش Query plannerمیگه (البته در داکیومنت PostgeSQL هم Planner و هم Optimizer عنوان شده). توی SQL Server و MySQL تحت عنوان Query Optimizer شناخته میشه و Oracle هم به Optimizer اکتفا کرده. من اینجا PostgreSQL رو مبنا قرار دادم. چون قراره بیشتر راجع به اون صحبت کنیم.
دو نوع کلی برای query plannerها وجود داره:
Rule Based:
از مجموعه قوانین مشخص برای ایجاد پلن استفاده میکنن. به عنوان مثال، این که همیشه از ایندکس برای جستجو استفاده کنن.
Cost Based:
از بین چندین پلنی که برای بازیابی داده ها تولید میکنن، اونی رو که فرض میکنن هزینه کمتری داره رو انتخاب میکنن. برای مثال ممکنه در سناریویی، اسکن کل جدول بهینه تر از بررسی ایندکس باشه. پس full scan table رو در اولویت قرار میده.
که اینجا ما بیشتر راجع به نوع دوم صحبت میکنیم و همون طور که بالاتر گفتم،مبنای ما، کار کرد Query plannerای هست که PostgreSQL از اون استفاده میکنه.
همون طور که گفتیم، planner/optimizer این وظیفه رو داره که پلن های مختلف اجرای یک کوئری رو که به یک مجموعه داده میرسن رو تولید کنه و در نهایت یک پلن اجرایی بهینه رو برای اجرای کوئری انتخاب کنه و به Executor تحویل بده. برای این کار هم (در صورت امکان از نظر محاسباتی)، پلنر زمان هر کدوم از این روش ها رو محاسبه (یا تخمین) میزنه و در نهایت اونی که به نظر میرسه سریع تره انتخاب میشه.
البته همیشه انجام این محاسبات هم کم هزینه نیستند. به خصوص وقتی که پای تعداد زیادی JOIN در میان باشد! اینجا مسئله انتخاب یک کوئری پلن لزوما بهینه مطرح نیست. چرا که مدت زمانی که برای محاسبه زمان اجرای این کوئری پلن ها اونقدری زمانبر هست که انتخاب گزینه بهینه، خودش بهینه نباشه. برای همین انتخاب کوئری پلنی که زمان اجرای قابل قبول داشته باشه برای ما هم قابل قبوله. این کار در postgresql با Genetic Query Optimizer یا GEQO انجام میشه که مسئله رو به شکل مسئله فروشنده دورهگرد (traveling salesman problem که به اختصار به اون TSP گفته میشه) در نظر میگره و برای حل اون از الگوریتم ژنتیک (GA) استفاده میکنه. جزئیات بیشتر راجع به این ماژول رو میتونین اینجا بخونین (که البته از سوادم فعلا خارجه :)). راجع به کوئری هایی که در اون دو یا چند جدول باهم نیاز هست که JOINبشن، نحوه محاسبه به این صورته که زمان اجرای هر کدوم از رابطه ها به صورت جداگانه محاسبه میشه و بعد هزینه انجام JOIN بین اون ها در محاسبات وارد میشه. جزئیات این قسمت با توجه به این که سه نوع استراتژی JOIN وجوود داره زیاده. میتونین باقیش رو اینجا بخونین.
سعی کردم که یک توضیح کلی راجع به این که پلنر چیه و چطوری کار میکنه و این که RDBMSچطور از اون برای بازیابی اطلاعت استفاده میکنه بدم. با این حال بنظرم بهتره خودتون هم چند نمونه از این پلن ها رو ببینین. برای این کار از ابزار هایی که RDBMSای که باهاش کار میکنین در اختیارتون قرار میده میتونین استفاده کنین. مثلا در PostgreSQL، دو ابزار
explain و explain analyze برای این کار تعریف شدن (با این تفاوت که دومی کوئری رو واقعا اجرا میکنه و زمان و نحوه اجرای واقعی اجرا رو بهتون نشون میده اما explain زمان تخمینی اجرای کوئری و نحوه اجرای اون رو بهتون نشون میده). برای توضیح بیشتر و دیدن مثال از این ابزار، این لینک رو مطالعه کنین.