با توجه به اینکه برنامه های زیادی رو دیدم و نمی خوام دوستان این مشکل ها رو داشته باشن یکسری توضیحات اضافه تر از نیارهای سوال کننده رو هم می دهم.
- اول اینکه ما نمی دونیم تعداد رکورد های خروجی select ما چندتاست پس فقط می تونیم بگیم تعداد رکورد ها در هر صفحه چندتا باید باشه. برای صفحه بندی فقط و فقط تعداد کل رکورد ها رو لازم داریم چرا؟ فرض کنید تعداد کل رکوردها 37 تا هست و ما قراره در هر صفحه 10 رکورد داشته باشیم در این صورت تعداد کل صفحات 4 تا خواهد بود.
- دوم اینکه select رو به چه شکلی بنویسیم و به چه شکلی تعداد کل رکوردها رو برای صفحه بندی بدست بیاریم.
در همه پروژه هایی که تا الان دیدم برای صفحه بندی و نمایش رکورد ها، یکی از دو روش زیر رو استفاده می کنن که من بهتون توصیه نمی کنم چرا؟ بخاطر گرفتن حافظه بیش از اندازه و یا اجرای تکراری یه دستور.
فرض کنید قراره select ی که دارای 3 تا join هست رو نمایش بدیم افراد یکی از دو روش زیر رو استفاده می کنن
الف) گروه اول میان یه select با تمام شرط ها و join ها می زنن بدون اینکه از دستور limit استفاده کرده باشن (واقعا شاهکاره!!!)
select users.*, profiles.*, comments.*
from users join profiles ... join comments ... where ...
اینطوری تعداد کل رکورد ها رو توی php با دستور count بدست میارن و در یه حلقه for میان اطلاعاتی که در اون صفحه لازمه نمایش مدن.
اشکال این روش کمبود حافظه هست خوب فرض کنید در بدترین حالت از ظرفیت فیلدهای یه رکورد استفاده شده باشه مثلا هر رکورد جدول users برابر 512 بایت، profiles برابر 512بایت و comments برابر 1024بایت باشه. 2KB برای اتصال یک سطر از 3 جدول حالا فکر می کنید یه ram چه تعداد رکورد می تونه در خودش نگهداری کنه البته در صورت نیاز می تونه از هارد هم استفاده کنه اما ... .
ب) گروه دوم از روش مناسب و معقول تری استفاده می کنن . ابتدا میان دستور select رو با limit اجرا می کنن
select users.*, profiles.*, comments.*
from users join profiles ... join comments ... where ... limit 0,10
بعدش در یه select دیگه البته بدون Limit میان از دستور count خود mysql استفاده می کنن
select count(users.*, profiles.*, comments.*)
from users join profiles ... join comments ... where ...
اشکال این روش اینه که یه دستور با این همه شرط و join دوباره باید اجرا بشه که از نظر سرعت بهینه نیست.
راه حل: برای رفع این مشکلات از SQL_CALC_FOUND_ROWS در دستور select استفاده می کنیم
select SQL_CALC_FOUND_ROWS users.*, profiles.*, comments.*
from users join profiles ... join comments ... where ... limit 0,10
SQL_CALC_FOUND_ROWS به mysql میگه تعداد کل رو بدون limit برای من یه جا نگهداری کن. بعد از دستور بالا برای بدست آوردن تعداد کل از دستور select FOUND_ROWS() می تونیم استفاده کنیم
select FOUND_ROWS()
حالا مثلا کاربر روی صفحه 5 کلیک کرده ما باید 10 رکورد پنجم از خروجی رو نمایش بدیم.
برای بدست آوردن نقطه شروع دستور limit، شماره صفحه یعنی 5 رو در تعدادی که قراره در هر صفحه نمایش داده بشه یعنی 10 ضرب می کنیم. و با توجه به اینکه اولین رکورد ما در دیتابیس دارای اندیس صفر می باشد پس باید از خروجی بالا یکی کم کنیم یعنی 5*10 منهای 1
select SQL_CALC_FOUND_ROWS users.*, profiles.*, comments.*
from users join profiles ... join comments ... where ... limit 49,10
limit 49,10 یعنی از رکورد 49 شروع کن و 10 تا رکورد رو در خروجی به من نمایش بده.