برگزیده های پرشین تولز

۷۰۰ میلیون رکورد دیتابیس را به راحتی آب خوردن با PHP پردازش کنید

mhm007_007

Registered User
تاریخ عضویت
29 دسامبر 2005
نوشته‌ها
1,248
لایک‌ها
184
سن
33
محل سکونت
tehran
تو جدیدترین پروژم باید تمام رکوردهای یک جدول دیتابیس MySQL رو پردازش میکردم که حدود ۷۰۰ میلیون رکورد داشت با کد زیر کار رو شروع کردم

$pdo = new PDO('mysql:dbname=db_name;host=127.0.0.1', 'root', '');
$stmt=$pdo->prepare('select * from table_name');
$result= $stmt->execute();
while($row=$stmt->fetch())
...do​
که خیلی سریع ۸ گیگ رم سیستمم پر شد و کار انجام نشد بعد از بررسی متوجه شدم که وقتی کد به تابع execute میرسه رم پر میشه و دیگه به حلفه while نمیرسه که نتایج رو پردازش کنه، مشکل به این خاطر بود PDO به صورت پیش فرض از buffered queries استفاده میکنه بزارید buffered queries و unbuffered queries رو توضیح بدم.


تو buffered queries وقتی تابع execute اجرا میشه MySQL نتایج رو به PHP میفرسته و کل رکوردهای حاصل در حافظه نگه داری میشه که تو مرجله بعد میشه با fetch یا fetchAll اونها رو پردازش کرد به همین دلیل بود که کل ۸ گیگ رم سیستمم پر می شد حالا اگه از unbuffered queries استفاده کنیم (که میگم چجوری فعالش کنید) وقتی تابع execute اجرا بشه MySQL یک resource به PHP برمیگردونه و نه کل نتایج رو، بعد شما با استفاده از تابع fetch میتونید دونه دونه رکوردها رو پردازش کنید و یا با تابع fetchAll کلشون رو بارگزاری کنید (که میشه عین مورد اول که کل نتایج تو حافظه قرار میگیرن و رم دوباره پر میشه)

برای اینکه buffered queries رو غیر فعال کنید باید به کد زیر رو بزنید

$pdo->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
هر کدوم از این روش ها مزایا و معایب خودش رو داره

  • تو buffered queries میتونید از توابعی مثل rowCount استفاده کنید چون کل نتایج مشخص شده هست ولی تو unbuffered queries همچین چیزی وجود نداره چون تعداد نتایج مشخص نیست چون همشون بارگزاری نشدن و از معایبش هم همین که چون کل نتایج تو حافظه قرار میگیرن باعث میشه استفاده زیادی از رم بشه.
  • unbuffered queries هم مزیتش بهینه سازی حافظه هست و از معایبش هم اینکه دو تا کوئری رو همزمان نمیتونید اجرا کنید به این خاطر که وقتی کوئری اول اجرا میشه و MySQL یک ریسورس برمیگردونه حالا اگه یک کوئری دیگه اجرا کنید MySQL نمیتونه هندل کنه مگه اینکه با تابع closeCursor قبلی رو ببندید مثل کد زیر
$stmt->closeCursor();​
نکته آخر اینکه ممکن هست درایور MySQL سیستمتون با توجه به تسخش از این قابلیت پشتبانی نکنه که اگه اینجوری باشه خطایی میده کاملن مشخص هست.

بعد از حل این مشکل، من یک کتابخونه به نام ridona نوشتم که هم میتونه دیتابیس های حجیم رو بخونه همفایهای متنی با حجم بالا رو که اینجا میتونید نحوه استفاده از اون رو ببینید.
 

fsohrabiii

کاربر تازه وارد
تاریخ عضویت
18 دسامبر 2017
نوشته‌ها
1
لایک‌ها
0
سن
31
خیلی عالی بود. از سایر دوستان هم دعوت می کنم تجربیات خودشون رو درزمینه طراحی سایت این تاپیک با بقیه به اشتراک بذارن.
 

ata.m

کاربر تازه وارد
تاریخ عضویت
6 می 2012
نوشته‌ها
76
لایک‌ها
27
خیلی مفید بود. ممنون.
 
بالا