با قسمت آخر از دوره ی آموزشی کار با رابط PDO در خدمت شما هستیم. در این قسمت به سراغ مبحث mysqlnd و کوئری های بافر شده می رویم.
اخیرا تمام extension های PHP که با پایگاه داده ی MySQL کار می کردند بر اساس یک کتابخانه ی سطح پایین (low-level) به نام mysqlnd
بروز رسانی شده و جایگزین کلاینت libmysql
شد. این بروزرسانی باعث بروز برخی تغییرات در رفتار PDO شد.
یکی از این تغییرات بحث buffered queries (به معنی کوئری های بافر شده) است. احتمالا تا به حال این نام به گوشتان نخورده است اما مطمئن باشید که بارها از این قابلیت استفاده کرده اید. متاسفانه خبر بد این است که برخلاف نسخه های قدیمی PHP که در آن از کوئری های بافر شده به شکل آزادانه استفاده می کردیم، نسخه های جدید که بر پایه ی mysqlnd driver هستند چنین اجازه ای به شما نمی دهند.
When using libmysqlclient as library PHP's memory limit won't count the memory used for result sets unless the data is fetched into PHP variables. With mysqlnd the memory accounted for will include the full result set. source: php.net
ترجمه:
هنگامی که از libmysqlclient به عنوان کتابخانه استفاده می کنید، محدودیت حافظه ی PHP، حافظه ی اشغال شده توسط result set ها را نادیده می گیرد مگر آنکه داده ها از طریق یک متغیر fetch شوند. چنانچه از mysqlnd استفاده کنید، حافظه شامل تمام result set خواهد بود.
تمام این مسئله در رابطه با یک result set است. اگر یادتان باشد در جلسات قبل اشاره کردیم که result set ها (به معنی مجموعه نتایج) تمام ردیف هایی هستند که توسط یک کوئری پیدا می شوند.
هنگامی که کوئری SELECT اجرا می شود، دو راه برای ارائه ی نتایج در اسکریپت شما وجود دارد:
هنگامی از روش بافر شده استفاده می شود، تمام داده هایی که توسط کوئری برگشت داده می شوند، به صورت یک جا وارد حافظه (memory) اسکریپت می شوند اما در حالت بافر نشده یک پایگاه داده ردیف های پیدا شده را تک به تک تحویل اسکریپت می دهد.
بر همین اساس می توان گفت در حالت بافر شده، result set ها همیشه باری به دوش حافظه و سرور هستند، حتی اگر fetching شروع نشده باشد. به همین خاطر است که پیشنهاد می شود بیشتر از نیازتان درخواست نکنید و اگر به طور مثال به 20 نتیجه نیاز دارید، طوری کد بنویسید که تنها 20 نتیجه را دریافت کنید، نه اینکه 50 نتیجه را دریافت کرده و سپس 20 تا از آن ها را جدا کنید.
البته این مشکل، زمانی که کلاینت های قدیمی و برپایه ی libmysql استفاده می شدند، زیاد به چشم کاربران PHP نمی آمد چرا که حافظه ی اشغال شده توسط result set در دستورات ()memory_get_usage
و memory_limit
محاسبه نمی شد، اما زمانی که mysqlnd معرفی شد همه چیز تغییر کرد؛ هر راهی را برای دریافت نتایج انتخاب کنید باز هم result set ای که توسط کوئری بافر شده برگردانده می شود در دستورات ()memory_get_usage
و memory_limit
محاسبه خواهد شد.
به طور مثال ما هر دو حالت را روی یک سری داده پیاده سازی کردیم:
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, FALSE); $stmt = $pdo->query("SELECT * FROM Board"); $mem = memory_get_usage(); while($row = $stmt->fetch()); echo "Memory used: ".round((memory_get_usage() - $mem) / 1024 / 1024, 2)."M\n"; $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, TRUE); $stmt = $pdo->query("SELECT * FROM Board"); $mem = memory_get_usage(); while($row = $stmt->fetch()); echo "Memory used: ".round((memory_get_usage() - $mem) / 1024 / 1024, 2)."M\n";
خروجی به شکل زیر خواهد بود:
Memory used: 0.02M Memory used: 2.39M
بنابراین در کوئری های بافر شده، حتی اگر ردیف ها را تک به تک و دانه دانه دریافت کنید، حافظه باز هم اشغال خواهد شد!!
بر این اساس حتما یادتان باشد که هنگام انتخاب داده های بسیار بزرگ و حجیم، مقدار PDO::MYSQL_ATTR_USE_BUFFERED_QUERY
را روی FALSE
قرار دهید. البته این کار معایبی نیز دارد که مهم ترین آن ها عبارت اند از:
()rowCount
استفاده کنید (که تقریبا هیچ اهمیتی ندارد2).1- اگر با pointer ها آشنایی ندارید به قسمت "دریافت داده ها از طریق ()fetch" در مقاله ی انواع دریافت داده ها در PDO – قسمت اول مراجعه کنید.
2- در قسمت های قبل توضیح دادیم که رابط PDO تابعی به نام ()PDOstatement::rowCount
ارائه می دهد که تعداد ردیف های پیدا شده توسط کوئری را به شما برمیگرداند. این تابع بسیار به ندرت استفاده می شود و اگر بخواهم صادقانه تر بگویم احتمالا هیچ وقت در برنامه های عادی خود از آن استفاده نکنید. توسعه دهندگان مبتدی و حتی بعضا حرفه ای بیشتر اوقات برای شمردن چیزی از آن استفاده نمی کنند بلکه با آن چک می کنند تا ببینند داده ای برگشت داده شده است یا نه. این کار اشتباهی است! چرا که برای چنین مواقعی خود داده را دارید! یعنی از دستورات ()fetch
و ()fetchAll
استفاده کنید و دقیقا همین کار را برایتان انجام می دهند. برای مطالعه ی بیشتر به قسمت اول از مقاله ی ردیف ها (Rows) در پایگاه داده PDO مراجعه کنید.
3- با اینکه دو مورد اول مهم نبودند اما این مورد می تواند بسته به کار شما مهم باشد، بنابراین خوب به این مورد توجه کنید.
این قسمت، قسمت آخر از سری آموزشی رابط شیء گرای PDO بود و دوست دارم صمیمانه از شما که در این دوره همراه من بودید تشکر کنم. همانطور که قبلا به شما توضیح داده بودم، این دوره تنها به شکل تئوری طراحی نشده و در مباحث دوره از سوال های Stack Overflow و تجریبات برنامه نویسان قدیمی و حرفه ای در زمینه ی PDO استفاده شده است به همین دلیل شما تا اینجای کار دانش عملی بسیار خوبی (در حدود 90 درصد و بیشتر) از PDO دارید؛ امیدوارم بتوانید از دانش خود در زمینه های عملی و در بازار کار استفاده کنید.
دوست دارم قبل از پایان این جلسه به سوالات متداول شما پاسخ بدهم:
سوال: آیا این پایان PDO است و دیگر مقاله ای در این زمینه نخواهیم داشت؟
پاسخ: قطعا مقالات دیگری در زمینه ی PDO خواهم نوشت، مخصوصا مقالات عملی تر به همراه مثال و شاید مینی پروژه های دیگر. دلیل اینکه چنین مقالاتی را وارد سری آموزشی PDO نمی کنم این است که این مقالات به سیر آموزشی PDO مربوط نیستند و در واقع فوت های کوزه گری، نمونه کد های آماده، اشکالات رایج و ... خواهند بود که برای تازه کاران چندان مناسب نیست. مخاطب این مقالات افرادی هستند که با PDO آشنایی کامل داشته باشند.
سوال: چرا این دوره کوتاه بود؟ فکر می کردم PDO سخت تر از این حرف ها باشد!
پاسخ: متاسفانه باور اکثر برنامه نویسان همین است. برخلاف باور عمومی، مبحث PDO بسیار شیرین و کوتاه است چرا که پایه های آن، همان پایه های mysql و mysqli می باشد. در حقیقت شما چیز جدیدی یاد نمی گیرید بلکه دانش قبلی خود را بروزرسانی می کنید یا روش جدیدی برای استفاده از دانش قبلی خود پیدا می کنید و از همین جهت نیازی به دگرگون کردن ذهن خود ندارید. باور کنید یا نکنید، PDO به همین کوتاهی و سادگی است!
سوال: آیا با دانش فعلی خود می توانم وارد بازار کار شوم؟
پاسخ: بله! با کمی تمرین، کدنویسی شخصی و بررسی کدهای مختلف می توانید به راحتی وارد بازار کار شوید. خیالتان بابت امنیت استفاده از PDO نیز راحت باشد، از هر نظر چندین برابر از mysql و mysqli امن تر است.
سوال: آیا استفاده از PDO اجباری است؟
پاسخ: بگذارید اینطور بگویم، استفاده از mysql ممنوع! چرا که این رابط به طور کل منسوخ شده و حتی خود PHP نیز دیگر از آن پشتیبانی نمی کند. بین mysqli و pdo می توانید از هر کدام که خواستید استفاده کنید اما یادتان باشد که بین پراید و BMW نیز می توانید سوار هر کدام که خواستید بشوید! تنها مجوز استفاده از چیزی، آن را بهتر از بقیه ی چیز ها نمی کند، حکیمانه تصمیم بگیرید. بعید نیست که بعد از چند سال mysqli هم منسوخ شود!
امیدوارم از این سری آموزشی لذت برده باشید.
در پناه حق
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.