کارگران مشغول کار اند

script

درباره بهینه سازی sql کوئری با حل nested loop

برای حذف کردن یه سری row ها توی کوئری های خاصی از left join استفاده میکنیم. مثال زیر:

select * from tbl1
left join tbl2 on tbl2.key = tbl1.key
where tbl2.id is null

حالا اگر tbl2 همچین ساختاری داشته باشه:

create table tbl2 (id int primary key, key int);

باعث میشه اپتیمایزر رو به اشتباه بندازیم، به این شکل که چون id نمیتونه null باشه توی اون شرط where تعداد row های برگشتی از نود پایینتر رو کمتر حساب میکنه و این میتونه توی نودهای بالایی باعث اشتباه بشه.

مثال

همونطور که توی عکس پیداست تعداد ردیف های حدس زده شده اشتباهه

و این حدس اشتباه تا چند نود بالاتر تکرار میشه، و جایی مشکل اصلی شروع میشه که برای join با یه نود دیگه از nested loop استفاده میکنه!

حالا برای حل مشکل، بجای استفاده از id توی where از یه ستون دیگه هم استفاده میکنیم که nullable باشه. مثلا

where tbl2.column_2 is null and tbl2.id is null

نتیجه میشه:

همونطور که مشخصه تعداد row ها بیشتر حدس زده شد و از یه استراتژی دیگه استفاده کرد و کوئری من که حدود 10s طول میکشید الان 200ms کامل میشه!

نکته هایی که وجود داشت:

۱. توجه به nested loop

۲. پیدا کردن جایی که تعداد row های حدس زده شده که منجر به nested loop شده اشتباه هست

مدیکال استیودنت

پروژه مدیکال استیودنت از تاریخ ۷ تیر ۹۹ شروع شد. توی مذاکره های اولیه نظر من این بود که مدت زمان کار ۱ ماه باشه. اما خود کارفرما نظرش برای دو ماه بود، و چی بهتر از این؟‌ چون توی این بازه زمانی امتحان های دانشگاه هم بود، هر چند کلا ۸ ساعت برای همه امتحان ها وقت گذاشتم اما عذاب وجدانش راحتم نمیذاشت. پس قرار بر این شد که تا ۶ شهریور کار رو تحویل بدیم. تست شده، بدون مشکل(: و با کیفیت قابل قبول. خوشبختانه از قبل مدیریت یک سایت وردپرس رو انجام میدادن در نتیجه توی داکیومنت اولیه ای که بهمون داده شد یوز کیس ها رو لازم نبود تک به تک دوباره ازشون بپرسیم، پس مستقیم رفتم سر تحلیل کار. هفته اول هیچ کاری انجام ندادم و یادم نمیاد چرا (البته توی همین دو هقته اول چند تا فیچر جدید اضافه کردن،‌ یکی دوتا مورد هم تغییر دادن، که خوشبختانه این دیر شروع کردنه اینجا بدرد خورد)، توی هفته دوم کمی راجع به هسته اصلی پروژه فکر کردم،‌ که میشد مشاوره، یعنی رابطه ی دانش آموز با مشاور. دیزاین خودش توی ذهنم بود و در حد یه فیچرش رو uml کردم، ولی دیگه حوصله ام نشد! برای دیتابیسش از دیتاگریپ استفاده کردم. یک دیزاینی بهت نشون میده لذت میبری!

توی درایو فایلی درست کردم به عنوان Wiki برای نوشتن داکیومنت کار. اما اون هم همون اوایل زیاد آپدیت میکردم و دیگه از اواسط کار سمتش نرفتم. و الان پشیمونم! البته این که سمت داکیومنت کردن در ادامه کار نرفتم خب چون پروژه آنچنانی هم نبود و فکر کردم بیشتر اتلاف وقته. ولی اگر بود الان میتونستم قوانین سیستم رو یکجا داشته باشم، نه که بخوام توی کد دنبالش بگردم.

 

 

انتقال سایت از سرور قدیمی به سرور اصلی

هاست قدیمی که با دایرکت‌ادمین مدیریت میشد، شامل یه اپ وردپرس بود. خب برای جابجاییش گفتم که خودم براتون انجام میدم و چی بهتر از تجربه جدید. اول فکر میکردم کار سختی باشه، اما وقتی شروع کردم دیدم کلا کاری نداشت.

سرور های دی ان اس اینها همون شرکتی بود که ازش هاست میگرفتن. اول ازشون خواستم توی شرکتی که دی ان اس ارائه میده اکانت بسازن و اطلاعات سرور های فعلی رو وارد کنن. پس دی ان اس پرووایدر فعلی منتظر تغییر دی ان اس هست. وقتی دی ان اس رو عوض کردن، از نظر کارکرد هیچ تغییری رخ نداد. چون فقط آی پی های سرور قدیمی رو الان از دی ان اس پرووایدر جدید میگیره. بعد ازشون اجازه گرفتم که برای حدود نیم ساعت سایتشون پایین باشه، و اوکی دادن و مشکلی نداشتن. یه صفحه under maintenance کوچولو درست کردم و گذاشتم جای index فعلی، و از کل پوشه یه کپی گرفتم و انتقال دادم به سرور جدیده. بعد از دیتابیسشون خروجی گرفتم و توی دیتابیس جدید اینور ایمپورت کردم. بعد دی ان اس رو عوض کردم و روی آدرس جدید گذاشتم که ir بود. اولین مشکلی که خوردم این بود که دیگه وردپرس نمیتونست به دیتابیس وصل شه، رمز و یوزر جدید رو توی فایل کانفیگ تغییر دادم. وقتی وارد پنل شدم دیدم بعضی از پلاگین ها کار نمیکنه! با یکم جستوجو دیدم یکی از پلاگین ها برای دامنه com خریداری شده و روی دامنه جدید نمیاد. اینم به ساپورتشون یه تیکت زدن و حل شد. سر جمع ۱ ساعت طول کشید این انتقال دادن، و همه چیز مثل قبل کار میکرد.

 

درک نیازمندی ها

توی داکیومنت جایی گفته شد که تغییراتی مثل این که دانش آموز مشاوره اش رو لغو کنه،‌ یا تعلیق کنه،‌ یا یک ادمین مشاوری رو عوض کنه، توی پنل ادمین به صورت زیر قابل دیدن باشه:

- دانش‌آموز X مشاور خود را از Y به Z تغییر داد.

- ادمین مشاور X را تعلیق کرد.

در اولین نگاه به نظر میومد منظورشون Audit Log باشه، و من همین رو پیاده سازی کردم. البته جلوتر که رفتم متوجه شدم تحلیل اشتباهی بوده. چون در واقع چیزی که میخواست سابقه مشاوره ی یک دانش‌آموز بود،‌ و به صورت پیش‌فرض توی قسمت مشاوره همچین چیزی وجود داشت. هر دانش آموز یک دوره مشاوره داره، توی این دوره میتونه مشاور های مختلفی داشته باشه، هر مشاوره با یک مشاور میتونه وضعیت خاصی داشته باشه (تعلیق، فعال، شروع نشده)، و هر کدوم از این رکورد ها تاریخ شروع و پایان دارن. پس لیست مشاوره ها در هر دوره دانش آموز، با یک مشاور خاص،‌ میشه همین چیزی که به عنوان لاگ برداشت کرده بودم.

 

 

خیلی بهتره وقتی مشتری بهتون میگه فلان لیست رو و فلان اطلاعات رو میخوام ببینم، ازش بپرسید که چرا، میخوای با این اطلاعات چیکار کنی. اینجوری خیلی وقت ها میتونید این بخش از سیستم رو جوری که خودتون میدونید صحیح تره پیاده سازی کنید و نیاز مشتری هم پاسخ داده بشه. اما اینکه دقیقا همه اطلاعاتی که مشتری میگه رو مثلا نمایش بدین، ممکنه نیاز باشه n تا join بزنید و دردسر داشته باشه.

 

 

فنی

برای گرفتن یه لیست نیاز بود بر اساس سه تا فیلد مرتب سازی انجام بشه، همزمان هم با دوتا جدول دیگه جوین انجام بشه. این شکلی:
t1: id, other_fields

t2: id, other_fields

t1t2: t1_id, t2_id, created_at

همه رکورد ها باید بر اساس تاریخ به صورت نزولی مرتب بشن، یعنی آخرین رکورد بالاتر قرار بگیره. بعد همه اونهایی که t1_id مثل هم دارن کنار هم باشن، و اینایی که t1_id مثل هم دارن اگر توشون t2_id هم مثل هم باشه، این t2_id ها هم کنار هم باشه. کوئری رو با هم ببینیم:
1.
select * from t1t2
inner join t1 on t1.id = t1t2.t1_id
inner join t2 on t2.id = t1t2.t2_id
order by t1t2.created_at desc, t1t2.t1_id, t1t2.t2_id
به نظر میومد که کار کنه، ولی خب اونجوری که میخواستم مرتب نمیشد. جای فیلد های order رو عوض کردم ولی باز هم نشد. کوئری بعدی این شکلی بود:
2.
select * from (select * from t1t2 order by created_at desc) t1t2
inner join t1 on t1.id = t1t2.t1_id
inner join t2 on t2.id = t1t2.t2_id
order by t1t2.t1_id, t1t2.t2_id
اما این هم جواب نبود. دیگه در اوج نا امیدی که فکر کردم کلا دوتا مرتب سازی جدا از هم بنویسیم و کاربر هردفعه یکیش رو صدا بزنه، به لطف سعی و صحیح و خطا، این کوئری جواب داد:
3.
select * from (select * from t1t2 order by created_at desc) t1t2
inner join t1 on t1.id = t1t2.t1_id
inner join t2 on t2.id = t1t2.t2_id

بله، اصلا مرتبشون نکنی D: . باید حتما راجع به نحوه مرتب سازی دیتابیس بیشتر بخونم، منطق این ماجرا رو درک کنم. اینم بگم که اگر اون دوتا جوین رو انجام ندم، دیگه مرتب سازی درست انجام نمیشه!!


پایان کار

کار عملا ۲۴ شهریور تحویل داده شد. درحالی که قرار بود ۷ شهریور تموم بشه. خیلی از فیچر ها رو متاسفانه از قبل تست نکردیم و توی هفته آخر تحت فشار زیادی کار کردیم. همون مشکل شب امتحانی رو هنوز هم همراهمون داریم ظاهرا! البته دلیل این تاخیر فقط هم ما نبودیم، بعد از تموم کردن کارها کارفرما میخواست اطلاعات فعلی همه دانش‌آموز هاش رو همونطور که الان هست وارد سیستم کنه. و خب ما انتظار این رو نداشتیم، چون تاریخ ها باید بصورت دستی توی دیتابیس ذخیره میشد تا مشکلی پیش نیاد. بیش از ۴۰۰ تا دانش‌آموز و بیش از ۹۰۰ تا رکورد پرداخت باید ثبت می شد. نوشتن کدی که این اطلاعات رو همخوان با سیستم وارد کنه ۱ روز طول کشید. یک روز سخت! طرفای ظهر پدر هم متوجه شدن و میگفت فشار زیادی روته؟ داری چیکار میکنی مگه؟

خلاصه کده زده شد و طی سه مرحله وارد کردن دانش‌آموز ها و اطلاعات گذشته شون از توی فایل اکسل به دیتابیس، باگ هاش رفع شد.

 

تعهد ۸ ماهه کتبی و همیشگی شفاهی برای پشتیبانی از سیستمی که امروز تحویل میدم دارم. هم از نتیحه کار خودمون راضی بودم هم از کارفرما، پرداخت به موقع، اخلاق خوب، صبر، همکاری با ما در طول انجام کار. فکر میکنم حضور استک‌هلدر در طول یک پروژه، از مهمترین ویژگی های یک پروژه اجایل هستش.

 

 

Simplicity is the ultimate sophistication

سال دوم دانشگاه دانپرس رو شروع کردیم. با توجه به معلومات اون موقعمون تکنولوژی هایی که بنظرمون خوب بود رو انتخاب کردیم. اواسط یا شاید اواخر کار، از نظر علمی خیلی جلوتر از روز اول بودیم. کلی تکنولوژی جدید یاد گرفته بودیم و چندین تکنولوژی جدید هم توی این ۸ ماه کار بوجود اومده بود که خیلی خفن به نظر میومد. و من بعد از این مدت، از خستگی کار بود، یا از درجا زدن، که فکر میکردم از نظر فنی کلی اشتباه کردیم، اگر از فلان زبان استفاده میکردیم، اگر از فلان فریم‌ورک استفاده میکردیم، شاید الان وضعمون خیلی بهتر بود. ولی واقعیت این بود که توی بازاریابی و پیدا کردن نیاز مشتری، نحوه فروش و تبلیغات و پشتیبانی مشکل داشتیم. و از نظر فنی؟ اتفاقا بخاطر وسواس کار ها عقب می افتاد و به بقیه موارد هم ضرر میزد. شاید الان که دو ساله کاری روی پروژه نکردم هم مطمئنم از نظر امنیت و سرعت نیازی به نگرانی آنچنانی نداره ولی... نرم افزاری که کاربر نداره دقیقا چه نیازی به سرعت داره؟؟

این توهم بهینه بودن کار فنی، یکی از بزرگترین مشکلات ما برنامه نویس هاست. اگر کاری که داریم میکنیم استارت‌آپ باشه که دیگه گندی که میتونه بزنه بیشتر هم هست. چیزی که لازمه یه ساختار درست اولیه، سریع و تمیز جلو بردن کار، ریفکتور در صورت نیاز. کاش انرژی اضافه ای که برای سرعت و امنیت نرم افزار میذاریم رو برای معماری هزینه میکردیم.

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


عنوان:‌ Leonardo da Vinci

Known Bugs

توی یک سال گذشته یکی از تجربه هایی که حاصل شد درباره ی باگ های شناخته شده ی نرم‌افزاره، که نوشتنش اینجا حداقل برای یادآوری به خودم خوبه.

مهر سال ۹۸ بود که قرار شد وب سایت شرکت رو راه‌ اندازی کنیم. از اونجایی که از php فراری و توهم زدن هر پروژه ای از صفر ما رو در بر گرفته بود شروع کردیم کار رو با CSharp انجام دادن. نیازمندی اولیه معرفی شرکت و اعضاش و یک بخش اخبار و مقالات بود.

مثل هر پروژه دیگه ای در نگاه اول چیز خیلی ساده ای بود دیگه، یه تیبل میذاری و پست توش ذخیره میکنی اونور هم نمایش میدی. بقیه اش هم که فقط فرانته. با همین پیش زمینه شروع کردیم و نیازمندی های زیر در حین کار بوجود اومد:

- اتصال ادمین پنل به SSO

- آپلود یک/چند عکس برای پست

- WYSIWUG

- آپلود ویدیو برای پست

- دو/چند زبانه بودن وبسایت

- پست های جدا برای زبان های مختلف

- ترجمه یک پست، در زبان دیگه

- نمایش بعضی پست ها با یه الگوریتم خاص توی صفحه اصلی

- افزودن لینک آپارات و نمایش اون مثل بقیه عکس ها/ویدیو ها

 

اینها فقط فیچر های بزرگ قابل بیان بود، کلی ریزه کاری هم اضافه شد. خب این وسط، هر فیچر در زمان کمی درخواست میشد و پیاده سازی میشد، و نتیجه ای که داشت این بود که کد کار میکرد و تیمِ کسب و کار راضی بود. اما از نظر پیاده سازی بعضی مشکلات وجود داشت، یا یه چیزی رو میگفتیم اگر اینطور باشه درست تره، که چون اولویتی نداشت انجامش نمیدادیم. پس کلی مشکل شناخته شده توی سیستم بود (هست). گذشت و من که مسئول نگهداری از این نرم‌افزار بودم پروژه دیگه رو شروع کردم چون از نظر تیم سایت تکمیل بود و از نظر خودم اولویت پروژه جدید بیشتر از مشکلات سایت بود. الان هر چند هفته یکی از اون مشکلات خودش رو نشون میده و مجبور میشیم برگردیم و حلش کنیم. اما تفاوت چیه؟ که تمرکز ما از پروژه جدید به هم میخوره، حوصله انجام کار قدیمی رو نداریم، و بعد از انجامش حوصله برگشتن به پروژه جدید رو نداریم.

میخوام بگم که، اگر خیلی از اون مشکلات رو بجای توی ذهنم توی ترلو مینوشتم و همه میدیدیم که سایت چنین مشکلاتی رو داره، و حالا میخوایم اینها رو رها کنیم و بریم روی پروژه جدید، شاید جدی تر گرفته میشد، شاید از نظر یک نفر دیگه اولویتش بیشتر از پروژه جدید بود، و دچار این تلنبار نمیشدیم. چیزی که هست اینه که بهرحال مشکلاتی که برنامه نویس میدونه توی پروژه اش وجود داره باید حل بشه، حالا یا در برابر کار جدید مقاومت میکنه و اول اون مشکلات رو حل میکنه، یا در آینده مجبور به context switching میشه.

انتخابش با خودمونه. و من امروز یاد گرفتم بهتره کدوم رو انتخاب کنم.

ذخیره خودکار پست در بلاگ - کروم (موقتی)

اگر فیلد کاری شما نرم‌افزار باشه و توی ایران زندگی کنید، بجای خیلی از راه حل های دم دستی ای که بقیه توی کشور های دیگه به راحتی استفاده میکنن، مجبورید ابتکار به خرج بدین، یا کلی بگردید و یه راه دوم سخت پیدا کنید،‌ و به اصطلاح خودمون سکه ای سرش بزنید. در همین راستا یک عده هستن که به این وضعیت میگن:‌ آدم ها توی محدودیت رشد میکنن. اما چیزی که در واقعیت وجود داره اینه که این آدم ها معمولا از یک سطح مشخصی بیشتر رشد نمیکنن.

بگذریم، توی این پست یک ابزار رو معرفی کردم برای ذخیره خودکار پست، و گفتم که چرا هنوز نمیشه به راحتی روی کروم نصبش کرد. به عنوان راه حل موقتی، میتونید با انجام گام های زیر روی کروم هم نصبش کنید:

 

ذخیره خودکار پست در بلاگ

از رنج هایی که بعضی از کاربر های بلاگ میبرن، اینه که ممکنه بخاطر قطع برق، بسته شدن مرورگر و غیره متن بلندی که نوشتن بپره و معمولا کسی حوصله اش نمیشه دوباره بنویستش. با وجود درخواست های زیادی که به شرکت بیان شده این امکان رو هنوز پیاده سازی نکردن، نمیدونیم و کاری هم نداریم چرا.

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

 

شما میتونید برای فایرفاکس از اینجا و برای کروم از اینجا ابزاری که به عنوان extension نوشته شده رو روی مرورگرتون نصب کنید.

 

انتشار این ابزار برای کروم مستلزم ساختن اکانت دولوپر توی کروم وب ‌استور هستش،‌ و ثبت نام اکانت دولوپر مستلزم پرداخت 5$ هست، که متاسفانه فعلا امکان پرداخت خارج کشور برام(برامون) میسر نیست. اگر راهی پیدا شد حتما برای کروم هم منتشر خواهد شد.

 به عنوان راه حل موقتی برای نصب روی کروم این پست رو بخونید.

 

نحوه کار کردن با ابزار اینجوریه که:

 

۱) وقتی توی صفحه ارسال مطلب جدید یا ویرایش مطلب هستید، هر ۵ ثانیه یک بار همه متنی که نوشتید توی حافظه مرورگر ذخیره میشه.

۲) هر وقت که توی پنل وبلاگتون باشید، میتونید هرجای صفحه راست کلیک کنید، گزینه پست های ذخیره شده رو بزنید، و لیستی از متن هایی که قبلا ذخیره شدن رو ببینید.

 

همینقدر ساده(از دید من البته). چند تا نکته هم وجود داره:

- متن هایی که ذخیره میشن، بعد از ۲۴ ساعت از توی حافظه مرورگر حذف میشن. البته میشه این ساعت رو تغییر داد، ولی فکر نکنم نیازتون بشه.

 

امکانات دیگه ای که وجود داره:

- وقتی روی پست های ذخیره شده کلیک میکنید، میتونید زمانی که متن از حافظه مرورگر حذف خواهد شد رو ببینید، همچنین میشه از همونجا متن ذخیره شده رو حذف کرد

- از توی صفحه تنظیماتِ مربوط به extension میشه بعضی مقادیر مثل اون ۲۴ ساعت، یا اینکه هر چند ثانیه یبار متن ذخیره بشه، یا حتی رنگ و متن اون قسمتی که نشون دهنده وضعیت پست هست رو تغییر داد

 

محدودیت ها:

- ابتدا نحوه کار کردن این ابزار اینطوری بود که بجای ذخیره کردن توی حافظه مرورگر، بصورت خودکار روی اون دکمه ی سبز ذخیره کلیک میشد و پست به عنوان پیش نویس ذخیره میشد. بعد ظاهرا اگر این کار دفعات زیادی انجام میشد(هر ۱۰ ثانیه یبار مثلا)، سرور های بلاگ دیگه درخواست رو قبول نمیکردن و تا چند ساعت دسترسی به بلاگ با آی پی فعلی قطع میشد.

- علاوه بر مورد قبل،‌ ظاهرا اگر پستی رو به عنوان پیش نویس ذخیره میکردم سری بعد که انتشار میزدم دیگه توی لیست وبلاگ های بروز شده نمیومد، یه همچین چیزی، نمیدونم سناریو چجوری بود دقیقا.

 

به دلایل بالا و اینکه این پریدن پست حالا دیگه خیلی هم اتفاق نمی‌افته، به همین ذخیره کردن در مرورگر بسنده کردیم.

 

لطفا حتما توجه کنید:

هر کسی که کمی html/js بلد باشه میتونه extension بنویسه، extension میتونه تقریبا همه کارهایی که شما با کلیک توی مرورگر انجام میدید رو انجام بده. این یعنی هر extension که نصب میکنید باید از امنیتش کاملا مطمئن باشید. حالا اینکه چرا باید به این چیزی که من نوشتم اعتماد کنید رو دقیقا خودم هم نمیدونم، ولی مثلا میتونه این باشه که کد این extension اپن‌سورس هست و میتونید ببینید، (فکر کنم) بار اولیه همچین چیزی منتشر شده، یا اینکه از امکانات اختیاری بلاگ دامنه اختصاصی رو خرید کردم و قابل پیگیری ام :دی، و واقعا همه این ها میتونه باز هم دلیل قانع کننده ای نباشه..

 

طبیعتا این ابزار تا زمانی کاربرد داره که بلاگ امکان ذخیره خودکار رو اضافه کنه. برای بالاتر رفتن اون امنیتی که گفتم، همین الان هم توی تماس با بیان بهشون گفتم که اگر تمایل دارن مدیریت انتشار این ابزار رو بر عهده بگیرن(همچنان منتظر جوابم).

 

این هم اضافه کنم که از نظر قانونی نمیدونم اجازه داشتم از لوگوی بلاگ استفاده کنم یا نه، و یا این متن رو به صفحه اضافه کنم، باشد که ما رو ببخشن و برامون دردسر نشه.

هپی رایتینگ.

 

پ.ن لطفا اگه میخواید به دوستاتون معرفی کنید، آدرس همین صفحه رو بذارید نه آدرس مستقیم extension. تا همه یک منبع داشته باشیم که اگر مشکلی بوجود بیاد قابل رفع و رجوع باشه.

Designed By Erfan Powered by Bayan