انواع کوئری هایی که برای مدلهای مختلف که دارای ارتباط – همان join - با هم هستند، گرفته میشود، در فریمورک Yii دو راه وجود دارد، بارگذاری کند که به آن Lazy Loading گفته میشود و بار گذاری حریص که به آن Eager Loading گفته می شود. حالت بار گذاری حریص خود شامل دو روش: ۱- کوئری تکی، ۲- کوئری دوتایی، در فریمورک Yii می باشد.
بنا براین شما با تعیین with و toghether روش بارگذاری کوئری را مشخص می کنید.
در ادامه، یک مثال را در نظر میگیریم که دارای ارتباط یک به چند به این صورت است:
یک نویسنده دارای بی نهایت پست است.
یک پست متعلق به یک نویسنده است.
بارگذاری کند(Lazy Loading)
قطعه کد زیر، مثالی برای بارگذاری ساده می باشد:
$authors = Author::model()->findAll(); // fetches only the authors foreach($authors as $author) { echo "<h2>Author : " . $author->name . "</h2>"; echo "<ul>"; foreach($author->posts as $post) { // fetches the author's posts here echo "<li>" . $post->title . "</li>"; } echo "</ul>"; }
بدون تعیین ‘with’، متد ()Author::model()->findAll
فقط نویسندهها را واکشی می کند. پست های مربوط به هر نویسنده بعداً، زمانی که بخواهید به آنها بوسیله author->posts$
دستری داشته باشید، واکشی خواهند شد.
در اینجا یک کوئری یک به چند وجود دارد؛ به ازای واکشی یک نویسنده، چند کوئری برای واکشی پستهای آن نویسنده اجرا می شود.
کوئری اصلی شبیه به کد زیر است:
SELECT * FROM author;
آرایه نویسندهها توسط نتیجه این کوئری پر می شود. نوشتههای مربوط به نویسندهها در این مقطع هنوز واکشی نشده اند.
و کوئری چندتایی برای واکشی نوشتههای هر نویسنده شبیه به کد زیر است:
SELECT * FROM post WHERE author_id = X;
که X به شماره نویسنده در بانک اطلاعاتی اشاره دارد.
با استفاده از نتیجه واکشی شده این کوئری، Yii آرایه ای از نوشتهها را برای یک نویسنده پر می کند.
بارگزاری حریص-کوئری تکی(Eager Loading-Singe Query)
کد زیر مثالی برای بارگذاری کنترلی به روش کوئری تکی می باشد:
$authors = Author::model()->with('posts')->findAll(); // fetches the authors with their posts foreach($authors as $author) { echo "<h2>Author : " . $author->name . "</h2>"; echo "<ul>"; foreach($author->posts as $post) { // no query executed here echo "<li>" . $post->title . "</li>"; } echo "</ul>"; }
بوسیله تعیین ‘with’، در متد ()Author::model()->with('posts')->findAll
تمامی نوشتههای نویسنده یکجا واکشی میشوند و دیگر هیچ کوئری اضافهای به هنگام دسترسی شما با author->posts$
اجرا نمی شود، زیرا نوشتههای هر نویسنده اکنون واکشی شده است. با این حساب فقط یک کوئری اجرا شده است:
SELECT * FROM author JOIN post ON post.author_id = author.id;
قابل اشاره است که نتیجه این کوئری میتواند بسیار بزرگ باشد. زمانی که ۱۰۰ نویسنده در دیتابیس وجود داشته باشد و هر کدام هم ۵ نوشته داشته باشند، نتیجه بازگردانده شده شامل ۵۰۰ رکودر می باشد.
Yii برای پر کردن آرایه نویسندگان و نوشتههای آنها در یک لحظه در بین نتیجه میچرخد.
بارگذاری کنترلی – کوئری دوتایی(Eager Loading-Double Query)
در زیر مثالی برای بارگذاری کنترلی به روش کوئری دوتایی مشاهده می شود:
$authors = Author::model()->with('posts')->findAll(array('limit' => 10)); // fetches 10 authors with their posts foreach($authors as $author) { echo "<h2>Author : " . $author->name . "</h2>"; echo "<ul>"; foreach($author->posts as $post) { // no query executed here echo "<li>" . $post->title . "</li>"; } echo "</ul>"; }
در کد بالا متد، Author::model()->with('posts')->findAll(array('limit' => 10))
، فقط ۱۰ نویسنده به همراه نوشته هایشان را واکشی میکند و دیگر زمانی که شما با author->posts$
قصد دسترسی به نوشتهها را دارید، هیچ کوئری اضافهای اجرا نمی شود. این کد شبیه به مثال قبلی به نظر می آید. اما یک تفاوت بزرگ بین این دو وجود دارد.
در این مثال از دو کوئری در متد ()findAll
برای واکشی نویسندگان با نوشته هایشان استفاده شده است. زیرا Yii نمیتواند یک کوئری برای مرتبط کردن جدول نوشتهها مثل زیر را استفاده کند:
SELECT * FROM author JOIN post ON post.author_id = author.id LIMIT 10;
کد sql فوق ۱۰ رکورد را واکشی میکند، اما این به این معنی نیست که ۱۰ نویسنده را واکشی میکند بلکه زمانی اجرا میشود که هر نویسنده که ۵ نوشته داشته باشد، را واکشی می کند. بنابراین Yii ناچار به اجرای ۲ کوئری به صورت زیر است:
SELECT * FROM author LIMIT 10; SELECT * FROM post WHERE author_id IN (1, 3, 7, 10, ... X);
جایی که (۱, ۳, ۷, ۱۰, … X) یک آرایه از شماره نویسندههای واکشی شده در کوئری اولی می باشند.
Yii با چرخیدن بین ۲ مجموعه جواب واکشی شده، آرایه نویسندگان را به همراه نوشته هایشان پر می کند.
از کدام روش استفاده کنیم؟
اکنون ممکن است این پرسش پیش آید که Yii برای کوئری از جداول مرتبط از کدام روش استفاده می کند؟
برای جواب به این پرسش باید به قوانین زیر توجه کرد:
- اگر کلمه ‘with’ تعیین نشود => Lazy Loading.
- اگر کلمه ‘with’ تعیین شود => Eager Loading.
- اگر کلمه ‘together’ تعیین نشود
- در استفاده بانوع ارتباط BELONGS_TO و HAS_ONE => تک کوئری (Single Query)
- در استفاده با نوع ارتباط HAS_MANY و MANY_MANY
- با استفاده با کلمه ‘LIMIT’ و/یا ‘OFFSET’ => کوئری دوتایی(Double Query)
- بدون استفاده از کلمه ‘LIMIT’ یا ‘OFFSET’ => کوئری تکی(Single Query)
- مقدار together برابر با false باشد => کوئری تکی(Single Query)
- مقدار together برابر با true باشد => کوئری دوتایی(Double Query)
با استفاده از with و together در جای مناسب، میتوانید روش بارگذاری را تعیین کنید.
به یاد داشته باشید که یک جواب ساده برای استفاده از کدام روش در یک سناریو خاص وجود ندارد. در جایی ممکن است که Lazy Loading کارایی بهتری داشته باشد. این امر بستگی به دادههای شما و اینکه چه کار میخواهید با آنها انجام دهید دارد.
استفاده از Together یا عدم استفاده از Together
وقتی که شما با مدلهایی با نوع ارتباط HAS_MANY یا MANY_MANY کار می کنید، به ویژه در استفاده از CgridView یا ClistView، با مسأله مشکل و دشواری روبرو هستید.
اگر بخواهید نتیجه را در مدلی که دارای ارتباط است، با یک attribute خاص فیلتر کنید، باید از روش Eager-Loading و کوئری تکی استفاده کنید، وگرنه با خطای column not found error روبرو خواهید شد.
اما اگر بخواهید تعداد رکورد مدل اصلی را محدود کنید، باید از روش Eager-Loading و کوئری دوتایی استفاده کنید(یا Lazy-Loading).
در زیر مثالهایی برای استفاده از این روشها ارائه شده است:
wiki – Drills : Search by a HAS_MANY relation
wiki – Displaying, sorting and filtering HasMany & ManyMany relations in CGridView
نکته
عبارات «کوئری تکی» و «کوئری دوتایی» را خود نویسنده جهت فهم مطلب ارائه کرده است و از هیچ منبع رسمی استخراج نشده است.
و نکته بعد اینکه، این نوشته در نسخه ۱٫۱٫X فریمورک کاربرد دارد. Yii۲ نوع بارگذاری تک کوئری Eager-Loading را ندارد.
منبع: relational-query-lazy-loading-and-eager-loading-with-and-together
The post کوئری گرفتن داده ها در Yii appeared first on دست نوشته های یک تازه کار.