Hossam Assadallah

Hossam Assadallah Oracle APEX Architect
Designing Scalable ERP & POS Systems
PL/SQL Performance • Clean Architecture • Integrations
Founder @ GooAdmin
(1)

26/05/2026

"الله أكبر، الله أكبر، الله أكبر، لا إله إلا الله..
لبيك اللهم لبيك. مع تكبيرات العيد، أتمنى لكم ولعائلاتكم أياماً مليانة بالفرحة والراحة والسلام. ربنا يتقبل منا ومنكم صالح الأعمال، ويجعل أيامكم كلها أعياد. عيد أضحى مبارك! 🌙🤲"

23/05/2026

السلام عليكم يا شباب، كل سنة وأنتم طيبين وبألف خير بمناسبة قرب العيد، أعاده الله علينا وعليكم باليمن والبركات. ✨
حبيت أشارك معاكم تنويه سريع بخصوص سلسلة مقالات Orcan Theoretical Tuning. إحنا حالياً في فترة إجازة ومأنتخين شوية عشان نجدد الشغف والطاقة. 🔋💆‍♂️
إن شاء الله هنرجع نكمل بقية المقالات والدسم اللي فيها بعد العيد مباشرة وبقوة. 🚀

💡 شاركونا في التعليقات: إيه أكتر جزء عجبكم في السلسلة لحد دلوقتي؟ وإيه الأسئلة اللي حابين نجاوب عليها في المقالات الجاية؟

إجازة سعيدة على الجميع، واستمتعوا بالعيد! 🐑🎉

22/05/2026

لَن تَنَالُوا الْبِرَّ حَتَّىٰ تُنفِقُوا مِمَّا تُحِبُّونَ ۚ وَمَا تُنفِقُوا مِن شَيْءٍ فَإِنَّ اللَّهَ بِهِ عَلِيمٌ

22/05/2026

المقال الثامن: وحش الـ Subqueries.. سر الـ Unnesting وكيف يراك أوراكل 🧟‍♂️🔄
كثير منا يفضل كتابة الـ Subqueries (الاستعلامات الفرعية) لأنها أسهل في القراءة والمنطق. لكن هل تعلم أن أوراكل، في أغلب الأحيان، لا ينفذها كما كتبتها؟ المحرك يمتلك خاصية مذهلة تسمى Query Transformation، وأهم جندي فيها هو Subquery Unnesting.
1. ما هو الـ Subquery Unnesting؟
تخيل أنك كتبت استعلاماً يبحث عن الموظفين الذين يعملون في أقسام موجودة في "القاهرة":

SELECT last_name FROM employees
WHERE department_id IN (SELECT department_id FROM departments WHERE location = 'Cairo');

منطقياً، أنت تظن أن أوراكل سينفذ القوس أولاً ثم يبحث في الموظفين. لكن أوراكل يرى أن هذا "بطيء"! هو يقوم بفك القوس (Unnesting) وتحويل الاستعلام إلى Join عادي بين الجدولين لأن الـ Join يمنح الـ Optimizer خيارات أكثر (مثل Hash Join).
2. متى يصبح الـ Subquery "وحشاً" يلتهم الأداء؟
تصبح المشكلة حقيقية مع الـ Correlated Subquery (الاستعلام المرتبط)، وهو الذي يعتمد فيه القوس الداخلي على قيمة من القوس الخارجي.
أوراكل يضطر هنا (في بعض الحالات) لتنفيذ الاستعلام الداخلي لكل صف من الاستعلام الخارجي!
إذا كان لديك 100 ألف موظف، سيتم تنفيذ الاستعلام الداخلي 100 ألف مرة. هنا ستجد الـ ⁠Cost⁠ في الخطة قد انفجر.
3. السحر الجديد: الـ Semi-Join والـ Anti-Join
عندما تقوم بفك الـ Subquery الذي يحتوي على ⁠IN⁠ أو ⁠EXISTS⁠ في أوراكل، ستظهر لك عمليات غريبة في الـ Ex*****on Plan:
HASH JOIN SEMI: تعني أن أوراكل بمجرد أن يجد "أول تطابق" في الجدول الثاني، سيتوقف وينتقل للصف التالي (سريع جداً).
HASH JOIN ANTI: تظهر عند استخدام ⁠NOT IN⁠ أو ⁠NOT EXISTS⁠ لبحث الصفوف التي "لا تملك" مقابلاً.
4. فخ الـ NULL مع الـ NOT IN
هذا هو الفخ الذي يقع فيه كبار المحترفين. إذا كان العمود داخل الـ ⁠NOT IN⁠ يحتوي على قيمة واحدة ⁠NULL⁠ ولم تخبر أوراكل بفلترتها، فإن الاستعلام بالكامل قد يعيد صفر نتائج، وسيضطر أوراكل لاستخدام خطة تنفيذ بطيئة جداً تسمى ⁠FILTER⁠ بدلاً من ⁠Anti-Join⁠.
💡 نصيحة الخبراء:
دائماً ابحث في الـ Ex*****on Plan عن كلمة FILTER. إذا وجدتها فوق عملية ⁠TABLE ACCESS FULL⁠ لجدول ضخم، فهذا يعني أن الـ Unnesting قد فشل، وأوراكل ينفذ الـ Subquery آلاف المرات. في هذه الحالة، قد تحتاج لإعادة كتابة الكود يدوياً كـ Join أو استخدام الـ Hint المسمى ⁠/*+ UNNEST */⁠.

في المقال القادم:
سنتعلم كيف نطلق العنان لكل موارد السيرفر.. سحر الـ Parallel Processing. متى نستخدمه؟ وكيف نتجنب استهلاك السيرفر بالكامل؟
هل تفضل كتابة الـ IN أم الـ EXISTS؟ وهل لاحظت فرقاً في الأداء بينهما من قبل؟ 🏁🔥

20/05/2026

المقال السابع: معركة الـ Joins.. متى يكون الـ Hash Join أسرع من الـ Nested Loops؟ ⚔️🤝
في أوراكل، نادراً ما نستعلم من جدول واحد. السحر الحقيقي يحدث عند ربط الجداول (Joining). لكن الصدمة هي أن أوراكل لا يملك طريقة واحدة للربط، بل لديه "خوارزميات" مختلفة، واختيار الخوارزمية الخطأ قد يحول استعلاماً مدته ثوانٍ إلى دقائق.
في هذا المقال، سنفك الشفرة بين أشهر نوعين للربط في أوراكل.
1. الـ Nested Loops: "الطريقة التقليدية"
تخيل أن لديك قائمتين من الأسماء وتريد البحث عن الأسماء المشتركة. تأخذ الاسم الأول من القائمة "أ" وتبحث عنه في كل القائمة "ب"، ثم تأخذ الاسم الثاني وتكرر العملية.
متى يختارها أوراكل؟ عندما يكون أحد الجدولين صغيراً جداً (Driving Table) والجدول الآخر مفهرس بشكل جيد على عمود الربط.
الميزة: سريعة جداً في استخراج "أول مجموعة صفوف" (First Rows).
العيب: إذا كان الجدولين كبيرين، ستصبح العملية "جحيم I/O".
2. الـ Hash Join: "الوحش السريع للمجلدات الضخمة"
هنا أوراكل يقوم بحركة ذكية؛ يأخذ الجدول الأصغر ويقوم بعمل "خارطة طريق" له في الذاكرة (Hash Table)، ثم يمر على الجدول الثاني مرة واحدة فقط ليطابق البيانات.
متى يختارها أوراكل؟ عندما يربط جداول ضخمة (Millions of rows) ولا توجد فهارس كافية، أو عندما يحتاج لمعالجة البيانات بالكامل.
الميزة: كفاءة مذهلة في الـ Bulk Processing.
العيب: يستهلك مساحة في الـ PGA (الذاكرة الخاصة بالـ Session)، وإذا لم تكفِ الذاكرة، سيضطر لاستخدام الـ Temp Tablespace مما يبطئ العمل.
3. الـ Sort Merge Join: "الخيار الأخير"
أوراكل يقوم بترتيب الجدولين أولاً ثم دمجهما.
متى يختارها أوراكل؟ عندما يكون الربط ليس بعلامة "تساوي" (مثل ⁠> ⁠ أو ⁠< ⁠)، أو عندما تكون البيانات مرتبة مسبقاً.
4. كيف تكتشف "الفخ" في الـ Ex*****on Plan؟
افتح الخطة وابحث عن عمود الـ ⁠Operation⁠:
إذا رأيت ⁠NESTED LOOPS⁠ مع جدول فيه مليون صف بدون فهرس: أنت في مشكلة كبيرة! (أوراكل هنا سيعمل ملايين القراءات).
إذا رأيت ⁠HASH JOIN⁠ استغرق وقتاً طويلاً: افحص الـ ⁠Temp Space⁠؛ فربما الذاكرة المخصصة للاستعلام صغيرة جداً.
💡 نصيحة الخبراء:
ترتيب الجداول في الـ ⁠Nested Loops⁠ مصيري. الجدول الذي يبدأ به أوراكل يسمى Driving Table. تأكد دائماً من أن أوراكل يبدأ بالجدول الذي يحتوي على أقل عدد من الصفوف بعد الفلترة (Filter). إذا أخطأ أوراكل في الترتيب، يمكنك توجيهه باستخدام الـ Hint الشهير ⁠/*+ ORDERED */⁠ أو ⁠/*+ LEADING(table_name) */⁠.

في المقال القادم:
سنتعامل مع "وحش الـ Subqueries".. كيف يحول أوراكل استعلاماتك الفرعية إلى Joins؟ وما هو سر الـ Unnesting؟
هل لاحظت من قبل تحول استعلامك من Nested Loops إلى Hash Join بعد زيادة حجم البيانات؟ أخبرنا بتجربتك! 🏁🔥

18/05/2026

المقال السادس: تكنولوجيا الـ Histograms.. لماذا لا تكفي الإحصائيات العادية؟ 📊🤔
في المقالات السابقة، قلنا إن أوراكل يعتمد على الإحصائيات (Statistics) ليعرف حجم الجداول. لكن، هل سألت نفسك يوماً: "لماذا يختار أوراكل خطة تنفيذ عبقرية لقيمة معينة، بينما يختار خطة كارثية لقيمة أخرى في نفس العمود؟".
السر يكمن في توزيع البيانات (Data Skewness)، والحل الذي يقدمه أوراكل يسمى الـ Histograms.
1. الكذبة التي تصدقها الإحصائيات العادية
الإحصائيات العادية تخبر أوراكل بـ: (عدد الصفوف، أصغر قيمة، أكبر قيمة، وعدد القيم الفريدة).
تخيل جدولاً فيه مليون موظف، منهم 990 ألف في فرع "القاهرة" و 10 آلاف فقط في فرع "مطروح".
بدون Histogram: أوراكل سيحسب المتوسط، ويظن أن كل مدينة لها 500 ألف موظف.
النتيجة: لو بحثت عن "مطروح"، سيستخدم أوراكل ⁠Full Table Scan⁠ لأنه يظن أن هناك نصف مليون صف سيعود! وهذا خطأ فادح.
2. ما هو الـ Histogram وكيف ينقذنا؟
الـ Histogram هو إحصائيات متقدمة تخبر أوراكل عن "توزيع" القيم داخل العمود. هو يخبر المحرك: "يا أوراكل، احذر! البيانات ليست موزعة بالتساوي، قيمة (القاهرة) متكررة جداً، وقيمة (مطروح) نادرة".
3. متى يقوم أوراكل بإنشاء Histograms؟
أوراكل ذكي؛ هو لا ينشئ Histograms لكل الأعمدة (لأنها تزيد من وقت جمع الإحصائيات)، بل ينشئها فقط إذا توفر شرطان:
1 Data Skew: أن تكون البيانات غير موزعة بالتساوي.
2 Column Usage: أن يكون العمود قد استُخدم فعلياً في شرط ⁠WHERE⁠ في استعلامات سابقة.
4. أنواع الـ Histograms التي ستراها في الخطة:
عندما تشرح الخطة أو تنظر في جداول النظام (⁠DBA_TAB_COL_STATISTICS⁠) ستجد أنواعاً أشهرها:
Frequency Histograms: يستخدم عندما يكون عدد القيم الفريدة صغيراً (مثل الحالة الاجتماعية).
Top-Frequency & Hybrid: أنواع متطورة (ظهرت في 12c وما بعدها) للتعامل مع البيانات الضخمة والمعقدة.
💡 نصيحة الخبراء:
إذا وجدت استعلاماً يعمل بسرعة "أحياناً" وببطء "أحياناً أخرى" لنفس الكود مع تغيير القيمة فقط (Bind Variable Peeking)، فغالباً المشكلة في الـ Histograms.
الحل: تأكد من جمع الإحصائيات باستخدام ⁠DBMS_STATS⁠ مع خيار ⁠FOR ALL COLUMNS SIZE AUTO⁠ لترك أوراكل يقرر أين يحتاج لـ Histogram.

في المقال القادم:
سندخل في معركة الـ Joins.. متى يكون الـ Hash Join أسرع من الـ Nested Loops؟ وكيف تكتشف أن أوراكل اختار النوع الخطأ؟
هل واجهت مشكلة "توزيع البيانات" من قبل واضطررت لجمع الإحصائيات يدوياً؟ شاركنا قصتك! 🏁🔥

17/05/2026

المقال الخامس: الفهارس المتقدمة (Composite & Function-Based)
س9: في الفهرس المركب (Composite Index) على الأعمدة (A, B, C)، متى يكون الفهرس أكثر كفاءة؟
أ) عندما نستخدم العمود (C) فقط في شرط البحث.
ب) عندما نستخدم العمود (A) وهو "العمود القائد" (Leading Column) في شرط البحث.
ج) ترتيب الأعمدة لا يؤثر أبداً على كفاءة الفهرس في أوراكل.
س10: ما هي الفائدة الرئيسية من الـ Invisible Index؟
أ) جعل الفهرس يشغل مساحة أقل على الهارد ديسك.
ب) اختبار تأثير الفهرس على أداء استعلام معين قبل تفعيله بشكل كامل للنظام (تغيير آمن).
ج) منع المستخدمين من رؤية البيانات الموجودة داخل الفهرس

16/05/2026

المقال الخامس: خداع المحرك.. أسرار الـ Function-Based والـ Composite Indexes 🎭🔍
في المقال السابق، عرفنا لماذا يتجاهل أوراكل الفهرس أحياناً. اليوم، سنتعلم كيف "نصمم" فهارس ذكية تجعل المحرك (CBO) ينحني أمام كفاءة الكود الخاص بنا. سننتقل من مجرد إنشاء فهارس بسيطة إلى استراتيجيات الفهارس المتقدمة.
1. الـ Function-Based Index: الحل السحري للدوال
أكبر خطأ يقع فيه المبرمجون هو وضع عمود مفهرس داخل دالة (Function) في شرط الـ WHERE.
• المشكلة: إذا كان لديك فهرس على hire_date وكتبت:
WHERE TRUNC(hire_date) = '01-JAN-2023'
أوراكل سيتجاهل الفهرس تماماً ويقوم بعمل Full Table Scan.
• الحل: قم بإنشاء فهرس على "الدالة" نفسها!
CREATE INDEX idx_hire_date_trunc ON employees (TRUNC(hire_date));
بهذه الطريقة، يحفظ أوراكل نتائج الدالة في الفهرس، ويصبح الاستعلام في غاية السرعة.
2. الـ Composite Index: قوة الترتيب
الفهرس المركب (الذي يحتوي على أكثر من عمود) هو سلاح ذو حدين. السر ليس في "وجود" الأعمدة، بل في ترتيبها.
• قاعدة العمود القائد (Leading Column): أوراكل يفضل دائماً استخدام الفهرس إذا كان العمود الموجود في الـ WHERE هو أول عمود في الفهرس المركب.
• مثال: لو أنشأت فهرساً على (last_name, first_name):
• البحث بـ last_name سيكون طلقة 🚀.
• البحث بـ last_name و first_name معاً سيكون ممتازاً.
• البحث بـ first_name فقط؟ هنا قد يضطر أوراكل لعمل Index Skip Scan (وهي عملية جيدة لكنها أبطأ) أو يتجاهله تماماً.
3. الـ Index Only Access (الفهرس المغطى)
هذا هو أحد أعظم أسرار الـ Tuning. هل تعلم أنك تستطيع جعل أوراكل لا يلمس الجدول الأصلي أبداً؟
إذا كانت كل الأعمدة التي تطلبها في الـ SELECT موجودة داخل الفهرس المركب، فإن أوراكل سيجلب البيانات من الفهرس مباشرة ويقفل الملف.
• النتيجة في الخطة: ستجد INDEX FAST FULL SCAN بدلاً من الوصول للجدول، وهذا يوفر وقت الـ I/O بشكل مذهل.
4. الـ Invisible Indexes: التغيير الآمن
ميزة رائعة في أوراكل (من إصدار 11g وما بعده). هل تخشى أن إضافة فهرس جديد قد "يخرب" خطط تنفيذ استعلامات أخرى؟
• قم بإنشاء الفهرس كـ INVISIBLE.
• المحرك لن يراه ولن يستخدمه.
• يمكنك تفعيله فقط لجلسة العمل الخاصة بك (Session) لتجربته:
ALTER SESSION SET optimizer_use_invisible_indexes = true;
• إذا أثبت كفاءته، اجعله VISIBLE للجميع.
💡 نصيحة الخبراء:
لا تبالغ في عدد الأعمدة في الفهرس المركب. تذكر أن كل عمود إضافي يزيد من حجم الفهرس ويبطئ عمليات الـ INSERT والـ UPDATE. القاعدة الذهبية هي: "اصنع الفهرس الذي يخدم أكثر الاستعلامات تكراراً، وليس كل الاستعلامات".
📚 مصادرنا لهذا المقال (لتصبح خبيراً):
1. Expert Oracle Database Architecture - تأليف Thomas Kyte: يشرح بالتفصيل الممل كيف يتم تخزين البيانات داخل الفهارس المركبة.
2. Oracle SQL Tuning with Oracle SQLTXPLAIN - تأليف Stelios Vlasidis: مرجع رائع لفهم الـ Index Access Paths.
3. Cost-Based Oracle Fundamentals - تأليف Jonathan Lewis: لتعرف كيف يحسب أوراكل تكلفة الـ Index Skip Scan.
في المقال القادم:
سندخل في منطقة غامضة ومثيرة.. الـ Histograms. لماذا لا تكفي الإحصائيات العادية؟ وكيف يعرف أوراكل أن بياناتك "غير عادلة"؟
هل استخدمت الـ Composite Indexes من قبل وتعثرت في ترتيب الأعمدة؟ شاركنا تجربتك! 🏁🔥

15/05/2026

المقال الرابع: لماذا يتجاهل أوراكل الفهرس؟
س7: لماذا قد يختار أوراكل ⁠Full Table Scan⁠ رغم وجود فهرس على العمود المستخدم في الـ WHERE؟
أ) لأن أوراكل يكره استخدام الفهارس بشكل عام.
ب) لأن الاستعلام سيقوم باسترجاع نسبة كبيرة من بيانات الجدول (أكثر من 10% مثلاً).
ج) لأن الفهرس تم إنشاؤه بواسطة مستخدم مختلف.
س8: ما هي مشكلة استخدام الدوال مثل ⁠UPPER()⁠ أو ⁠TRUNC()⁠ على الأعمدة المفهرسة في شرط الـ WHERE؟
أ) تجعل النتائج غير دقيقة.
ب) تمنع الـ Optimizer من استخدام الفهرس التقليدي (B-Tree Index) وتؤدي لـ Full Table Scan.
ج) لا توجد مشكلة، أوراكل ذكي بما يكفي ليتعامل معها تلقائياً.

14/05/2026

يتجاهل أوراكل الفهرس؟ 🔍🚫
كلنا نعرف القاعدة التقليدية: "إذا كان الاستعلام بطيئاً، أضف فهرساً (Index)". لكن في عالم أوراكل الاحترافي، هذه القاعدة قد تكون بداية الكارثة! أحياناً تضع فهرساً وتفاجأ بأن أوراكل لا يزال يصر على عمل Full Table Scan. لماذا؟
في هذا المقال، سنفهم كيف يفكر أوراكل في الفهارس، ومتى يقرر أن وجود الفهرس مثل عدمه.
1. كيف يرى أوراكل الفهرس؟
الفهرس في أوراكل يشبه "فهرس الكتاب"؛ هو جدول صغير جانبي يحتوي على القيمة وعنوان مكانها في الجدول الأصلي (ROWID).
المشكلة ليست في الفهرس نفسه، المشكلة في "التكلفة". أوراكل يسأل نفسه: "هل الذهاب للفهرس ثم العودة للجدول لجلب باقي البيانات أرخص، أم قراءة الجدول كله مرة واحدة أرخص؟".
2. لماذا يتجاهل أوراكل الفهرس الخاص بك؟ (الأسباب الصادمة)
• انعدام الانتقائية (Low Selectivity): إذا كنت تبحث عن "الجنس" في جدول موظفين، والقيم هي فقط (ذكر/أنثى)، فأوراكل سيتجاهل الفهرس تماماً. لماذا؟ لأن الفهرس سيعيد له نصف الجدول، وقراءة نصف الجدول عبر الفهرس أبطأ بكثير من قراءته بالكامل مرة واحدة.
• استخدام الدوال (Functions) على الأعمدة: * خطأ: WHERE UPPER(last_name) = 'SMITH' (أوراكل لن يستخدم فهرس last_name).
• صح: استخدام Function-Based Index.
• الإحصائيات القديمة (Stale Statistics): إذا كان أوراكل "يعتقد" أن الجدول يحتوي على 10 صفوف فقط (بناءً على إحصائيات قديمة) بينما هو يحتوي على مليون، فسيختار Full Table Scan لأنه يظنه الأوفر.
• عدم المساواة (Inequality): استخدام != أو NOT IN غالباً ما يدفع أوراكل لتجاهل الفهرس.
3. أنواع الفهارس التي يجب أن تعرفها:
أوراكل لا يوفر فقط النوع التقليدي (B-Tree)، بل هناك أنواع أخرى لحالات خاصة:
1. B-Tree Index: النوع الافتراضي، ممتاز للقيم الفريدة (Unique) مثل رقم الموظف.
2. Bitmap Index: السحر الحقيقي في "مستودعات البيانات" (Data Warehouse) للقيم المتكررة (مثل الحالة الاجتماعية، المدينة).
3. Composite Index: الفهرس المركب (أكثر من عمود). وسره في ترتيب الأعمدة؛ العمود الأكثر استخداماً يجب أن يكون الأول.
4. قاعدة الـ 10% الشهيرة:
كقاعدة عامة (ليست مطلقة)، إذا كان الاستعلام سيعيد أكثر من 5% إلى 10% من إجمالي حجم الجدول، فمن المرجح جداً أن يتجاهل أوراكل الفهرس ويفضل الـ Full Table Scan.
💡 نصيحة الخبراء:
قبل أن تنشئ فهرساً جديداً، تأكد أولاً من الـ Ex*****on Plan. إذا رأيت Index Skip Scan فهذا يعني أن أوراكل يحاول استخدام فهرس مركب بطريقة ذكية رغم أنك لم تستخدم العمود الأول فيه. أوراكل ذكي جداً، لكنه يحتاج منك "إحصائيات" دقيقة ليعمل لصالحك.
📚 مصادرنا لهذا المقال (كن مرجعاً في فريقك):
1. Expert Oracle Database Architecture - تأليف Thomas Kyte: يشرح بعمق هندسة الـ B-Tree والـ Bitmap.
2. Oracle SQL Tuning Pocket Reference - تأليف Mark Gurry: مرجع سريع وممتاز لحالات استخدام الفهارس.
3. Effective Oracle by Design - تأليف Thomas Kyte: يوضح متى يكون الفهرس عبئاً على النظام وليس ميزة.
في المقال القادم:
سنتحدث عن "خداع المحرك".. كيف نستخدم الـ Function-Based Indexes والـ Composite Indexes لحل أعقد مشاكل الأداء.
هل قمت يوماً بإضافة فهرس واكتشفت أن الاستعلام أصبح أبطأ؟ أخبرنا بالقصة في التعليقات! 🏁🔥

100 ألف شكر لكل واحد فيكم! ❤️بفضل الله ثم دعمكم، سلسلة مقالات Oracle Tuning كسرت حاجز الـ 100,000 مشاهدة في وقت قياسي!ال...
13/05/2026

100 ألف شكر لكل واحد فيكم! ❤️
بفضل الله ثم دعمكم، سلسلة مقالات Oracle Tuning كسرت حاجز الـ 100,000 مشاهدة في وقت قياسي!
الأرقام اللي في الصورة دي بالنسبة لي مش مجرد "Views"، دي دليل إن المحتوى التقني الهادف لسه بخير، وإن المهندس العربي متعطش للمعلومة الحقيقية.
ليه تتابعنا لو لسه مشتركش؟
بنفك شفرات الـ Ex*****on Plan وبنخليها لعبة سهلة.
بنتعلم إزاي نرفع كفاءة الـ Database بأسرار الـ Tuning.
بنشرح التقيل ببساطة ومن غير تعقيد.
شكراً لكل واحد ساعد بكلمة حلوة أو "شير". اللي فات كان تسخين، واللي جاي أقوى بكتير! 🔥

Address

Hurghada Ras Gharib Road, الغردقة, البحر الاحمر, مصر
Hurghada

Alerts

Be the first to know and let us send you an email when Hossam Assadallah posts news and promotions. Your email address will not be used for any other purpose, and you can unsubscribe at any time.

Contact The Business

Send a message to Hossam Assadallah:

Share