قبل أكثر من شهر بقليل في موسكو ، تم عقد أكبر مؤتمر لمجتمع ما بعد اليونان PGConf.Russia 2019 ، والذي جمع أكثر من 700 شخص في جامعة موسكو الحكومية. قررنا نشر فيديو ونسخة من أفضل التقارير.
ولاحظ أن عرض
إيفان فرولكوف حول الأخطاء النموذجية عند العمل مع PostgreSQL كان الأفضل في المؤتمر ، لذلك سنبدأ به.
للراحة ، قسمنا فك التشفير إلى قسمين. في هذه المقالة ، سنتحدث عن تسمية غير متسقة ، وعن القيود ، وعن المكان الذي من الأفضل فيه تركيز المنطق - في قاعدة البيانات أو في التطبيق. سيتناول الجزء الثاني معالجة الأخطاء والوصول المتزامن والعمليات غير القابلة للإلغاء و CTE و JSON.

في شركتنا ، أشترك في دعم العملاء بشأن المشكلات المتعلقة بالتطبيقات ، أي ، أنا أساعد في حالات مشاكل الاتصالات ، مع تحسين الاستعلام وأشياء أخرى مماثلة. لقد رأيت ما يكفي من التطبيقات الأكثر تنوعًا. ما أنا فقط لم أر! ربما أكثر مما نود. جزء من ما سأقوله لا ينطبق فقط على PostgreSQL ، ولكن على أي قاعدة بيانات ، ولكن هناك شيئ ما على PostgreSQL.
كانت النتيجة الرئيسية التي تمكنت من استخلاصها من ما رأيته غير متوقعة إلى حد ما: في الواقع ، يمكن عمل أي تطبيق ذو ثبات مناسب. كان هناك مشروع رائع (لا أستطيع أن أذكر كل الشركات التي عملنا معها) حيث قام تطبيق أكثر من رائع بإنشاء جداول بالملايين. بدا الأمر كما يلي: يوم الاثنين ، يعمل النظام جيدًا ، ويوم الجمعة لا يعمل بشكل عملي. في عطلات نهاية الأسبوع ، يطلقون VACUUM FULL ، ويوم الاثنين يعمل بشكل جيد مرة أخرى. اتضح أنه يمكنك السخرية من PostgreSQL مثل هذا ، وكل هذا سيعيش ويعمل لبعض الوقت. قام رفيق آخر بشيء غريب: تم بناء كل شيء على مشغلات عليه ، ولم تكن هناك إجراءات على الإطلاق. وهذا يعني أن معظم الجداول لا يمكن لمسها ، ولا يمكن القيام بشيء ما ، ولكن هذه القاعدة قد عاشت أيضًا.
وأوضح ذلك بهذه الطريقة: "تنتقل القاعدة من حالة متسقة إلى أخرى ثابتة. إذا قمت بإعادة تحميل البيانات ، فستتوقف. ولكن بما أن لدي مشغلات ومفتاح فريد ، فلا يمكنني إعادة تدوير البيانات. " النهج غريب ، لكن في نفس الوقت يكون له معنى. ربما كان من الضروري القيام بعمل مختلف ، ولكن من الضروري أيضًا مراعاة ميزات العملاء. الخطأ الأول الذي سأتحدث عنه هو:

هنا مثال حقيقي واجهته. على الشريحة ، ترى كيف تم تسمية نفس الكيان في أعمدة مختلفة. يمكن للمرء أيضا مع المساحات. الكائنات الأخرى تمت تسميتها أيضًا بشكل غير متسق. إذا كنت بحاجة إلى أخذ شيء ما في جدول آخر ، فأنت بحاجة إلى معرفة ما يسمى هناك ، فهل هو نفسه. إذا كان لديك id_user و user_id في نفس الجدول ، فسيبدأ العمل بالبحث: ماذا يعني كل ذلك.
بالنسبة للعملاء الآخرين ، تم تسمية جميع الكائنات على هذا النحو: حرفين ، ثم خمسة أرقام. يجب أن أقول أنه لم يكن "1C". لماذا فعلوا هذا - لا أعرف: لم يكن هناك منطق في ذلك ، ولكن من أعمالي تحسين الاستعلامات.
مثال آخر: جزء من الأسماء باللغة الروسية ، جزء من اللغة غير الروسية ، ولكن بنوع من اللهجة الروسية. هذا يجعل الفهم صعبا ويخلق أخطاء جديدة. أنا نفسي أحاول تسمية الأعمدة كما لو كنت أعول على خدمة ، أي من أسماء الأعمدة هذه ستقوم تلقائيًا بإنشاء أسماء أعمدة عادية في بعض التقارير. في الحياة الواقعية ، للأسف ، ليس من الناجح جدًا أن يتم تحديد الاسم بشكل متسق - بما في ذلك لي. هذا صعب بشكل خاص مع التنمية الجماعية. ولكن يجب علينا أن نسعى جاهدين.
سبب مهم آخر للتسمية بالتسلسل: تتوفر أسماء الكائنات من خلال طلبات بيانات التعريف ، أي أن الأسماء هي أيضًا بيانات. ستتمكن من كتابة طلب وتحديد ، على سبيل المثال ، كل الصور - بشكل عام ، كل الصور - من قاعدة البيانات.

بيانات التعريف الصافية مريحة للغاية. خاصة عندما تفكر في المشكلات النموذجية المتعلقة بالوثائق - وفي تجربتي ، عادة ما تكون الوثائق إما غائبة أو غير كاملة أو غير صحيحة أو كلاهما: لأن مهمة كتابة الوثائق الجيدة قابلة للمقارنة في التعقيد بمهمة كتابة التعليمات البرمجية نفسها. لذلك من الأفضل أن تكون الشفرة ذاتية التوثيق. يساهم في ذلك تسمية منطقية متسقة للكائنات ، وعندما لا يكون هناك شيء واضح ، يجب عليك كتابة رمز المقتطف ومشاهدة كيفية عمله. بمجرد أن لا يكون هذا شيئًا ، لا شيئًا ، ولكن عندما تفعله طوال اليوم ، فهذا مرهق.

الحالة الحقيقية: كانت المؤسسة الجادة التي عملنا معها لديها قاعدة سير عمل على Oracle. انتقلنا إلى بوستجرس. أحد شروط العقد هو أننا نفرض مفاتيح أجنبية. لم يكونوا هناك ، وللأسف ، لم نتمكن من فرضها: اتضح أن الجداول بها الكثير من الصفوف "اليسرى" ، ولا أحد يعرف ما يجب فعله بها ، بما في ذلك العميل.
عندما لا تحتاج إلى إلقاء نظرة على أشرطة التقدم ، ولكن العمل مع المستندات لدفع الأموال ، فإن الموقف يكون محزنًا. يساعد الكثير عندما يقوم المبرمج ، بموجب العقد ، بدفع ثمن الأخطاء بنفسه ، ومن المستحسن أن تكون المبالغ كبيرة - ثم يحدث التنوير في غضون دقائق ، وربما خمسة عشر. تظهر المعوقات فورًا ، ويبدأ فحص كل شيء على الفور.
حتى أنك لا تتخيل (حسناً ، ربما شخص ما يتخيل بالفعل) كم هو أكثر ملاءمة للتعامل مع القضية عندما فشل الدفع ، وليس عندما تمر ، ولكن ليس هناك. خاصة إذا كانت الكمية كبيرة. هذا هو من تجربة شخصية.

من ناحية أخرى ، يمكن للمرء أن يسمع في كثير من الأحيان أن القيد يقلل من الأداء. نعم ، إنهم يفعلون ذلك ، ولكن إذا كنت تريد الحصول على البيانات الصحيحة ، فليس هناك ببساطة خيارات أخرى لك. إذا كان لديك تطبيق يأخذ في الاعتبار عدد زيارات العملاء إلى المتجر ، فقد تكون هناك معلومات غير دقيقة لن تؤثر على الإحصائيات خاصةً ، وإذا عدنا الأموال ، ستكون القيود ضرورية.
عادة ما يتم إنشاء أسماء القيد بواسطة ORM أو النظام ، وعادة ما لا أحد يضايق على وجه التحديد قيود الاسم - ولكن دون جدوى! عندما تستمر في معالجة الخطأ ، باسم القيد ، يمكنك إعطاء رسالة واضحة للمستخدم ، وتصنيف الخطأ وإعلامك بما إذا كنت تريد إجراء العملية مرة أخرى ، أو ما إذا كانت هذه العملية لم تعد ضرورية ، أو ببساطة لا يمكن تكرارها.
شيء آخر لم أره ، لكنني أوصي به بشدة: بالنسبة لجميع عمليات التدقيق المالية (وليس المالية فقط) ، يجب أن يكون هناك عمليتان على الأقل. والحقيقة هي أنه عاجلاً أم آجلاً سوف تدخل في شيء لتغيير الرمز ، وقد يكون من الجيد جدًا كسر أحد الشيكات. ثم الثاني سيوفر لك. إذا فعلت ثلاثة ، فهذا ليس سيئًا أيضًا.

السؤال الذي يطرح نفسه في كثير من الأحيان: أين للتحقق من صحة البيانات. على العميل أو على الخادم؟ في رأيي ، من الواضح أنك تحتاج إلى التحقق من هناك وهناك. لديك خطأ في العميل ، ثم الخادم ليس كذلك
ستفقد ، أو لديك خطأ على الخادم ، ثم سيساعد العميل على الأقل في تتبعه. السؤال قابل للنقاش إلى حد ما ، ونحن ننتقل بسلاسة إلى الموضوع: أين نحافظ على المنطق الأساسي: في التطبيق أو في قاعدة البيانات؟
إنه ملائم في قاعدة البيانات لأنه ، حسب تجربتي ، يقوم عمل ما بانتظام بإصدار تغييرات عاجلة: قم بإزالة هذا أو إدخاله وهذه الثانية للغاية. إذا كان لديك منطق في الشفرة المترجمة ، فأنت بحاجة إلى جمع ونشر ومعرفة ما حدث. في كثير من الأحيان هذا هو ببساطة مستحيل. في قاعدة البيانات ، وهذا هو أكثر ملاءمة. ولكن هناك قول مأثور مشهور: مبرمجو فورتران ذوو الخبرة يكتبون في فورتران بأي لغة. يتم كتابة حوالي 80 رمز خادم بأسلوب إجرائي تمامًا: لدينا الوظيفة "get_user ()" وتقوم بإرجاع النوع "مستخدم" ، وإذا كان "get_list_users ()" ، فسوف تُرجع مجموعة من "المستخدمين". هو حقا أكثر ملاءمة لكتابة مثل هذه الأشياء في جاوة من SQL أو pgsql.

من ناحية أخرى: لماذا تحتاج إلى وظيفة "get_user ()"؟ يمكنك فقط أخذها في جدول أو في طريقة عرض. نظرًا لأن لديك قاعدة بيانات علائقية ، يجب أن تكتب ، كما يبدو لي ، علائقية. من المهم ، أولاً ، تحديد البيانات التي نعمل معها بوضوح: إذا كانت البيانات الخاصة بنا عبارة عن بيانات غير مقبولة أو غير صالحة ، فستكون النتيجة مناسبة ، وربما لا يجب قتلها. إذا كانت البيانات مهمة بالنسبة لنا ، إذا كانت أموالًا أو ممتلكات أو عمليات قانونية ، فهناك حاجة للقيد وكلما كان ذلك أفضل. أكرر: من الأفضل عدم إجراء العملية بدلاً من القيام بها بشكل غير صحيح. ولا تكتب التعليمات البرمجية الإجرائية في قاعدة بيانات علائقية: ستندم عليها كثيرًا.

رأيت جدولًا يحتوي على 30 ألف صف (منتجات) ، حيث تم تنفيذ الطلب "إظهار قائمة بالسلع ذات الصلة" لمدة ثانية تقريبًا. على ما يبدو ، تمكنوا من إنشاء مخطط قاعدة بيانات "جميلة ومعقدة". شخصياً ، أعتقد أنك إذا كنت تفعل شيئًا صعبًا للغاية ، فمن الأرجح أنك إما تقوم بشيء خاطئ أو لديك بالفعل مهمة صعبة للغاية. إذا كان لديك نوع من المتجر أو تطبيق منتظم للمحاسبة ، فمن غير المحتمل أن تكون هناك علاقات معقدة للغاية بين الكيانات.
عندما بدأت حياتي المهنية ، بدا أن الجدول الموجود في ملف DBF سعة 60 ميغا بايت في النظام المصرفي كبير جدًا ، والآن 60 ميغا بايت لا شيء على الإطلاق - الأجهزة أفضل ، والبرمجيات أفضل ، وكل شيء يعمل بشكل أسرع ، ولكن يبقى السؤال: أين تحصل على الكثير البيانات؟ قواعد منتفخة كبيرة جدًا وعادة ما تصبح كذلك بسبب المحفوظات. في أي DBMS وفي PostgreSQL ، تم بذل الكثير من الجهد لضمان تشغيل تنافسي متسق للتطبيقات. لا يتغير الأرشيف على الأرجح ، ولا تكون هناك حاجة على الإطلاق لإمكانيات DBMS للتعامل معه. يجدر التفكير في إخراجها من DBMS.

بين الحين والآخر مع نوع من الحول المفصلي ، يسألون السؤال التالي: هل سيسحب PostgreSQL قاعدة من هذا القبيل وكذا المجلد. لكن السؤال نفسه غريب هنا: يمكنك وضع البيانات في قاعدة البيانات بالطريقة التي تريدها ، طالما أن هناك مساحة كافية على القرص ، فسوف يكمن الكثير. والسؤال هو ، على سبيل المثال ، كيفية عمل نسخ احتياطي للمحفوظات على بايت ، ومكان وضع النسخة الاحتياطية الكاملة والمبلغ الذي ستأخذه. أظن بشدة أن متطلبات الحجم على الأقل ترتبط جزئيًا برغبة بائعي المعدات في بيعك أكثر.
إذا قمت بتخزين المستندات في قاعدة البيانات ، فمن غير المحتمل أن تقوم بمعالجتها هناك: يمكن بطبيعة الحال تعديل جدول بيانات Excel على الخادم ، لكن هذا يعد مهنة غريبة. على الأرجح ستكون هذه الملفات للقراءة فقط بشكل عام. من الأفضل تخزين روابط المستندات ، وأنفسهم في بعض وحدات التخزين الخارجية. في النهاية ، يمكنك الاحتفاظ بالتوقيع الرقمي للجدول - بحيث لا يتغير (إذا قررت المسائل التشريعية ذات الصلة).
ملاحظة أخرى: إذا لم يكن لديك بعض الأعمال الضخمة ، وليس نوعًا ما ، على سبيل المثال ، مؤسسة فدرالية ، فمن غير المحتمل أن يكون لديك قاعدة كبيرة جدًا. إذا كنت لا تخزن الفيديو فيه ، بالطبع.

سبب آخر أن قاعدة البيانات كبيرة فهارس غير الضرورية. قواعد بدون فهارس لم أقابلها ، لكن في كثير من الأحيان التقيت بقواعد حيث توجد عدة مؤشرات على نفس الأعمدة بنفس الترتيب. القاعدة تتيح لك القيام بذلك. عند إنشاء فهرس ، يرجى معرفة ما إذا كان يكرر فهرسًا حاليًا. يمكنك معرفة الفهارس غير المطلوبة من خلال النظر في pg_stat_user_indexes لمعرفة مدى فعالية استخدام الفهرس. ربما ليس مطلوبا على الإطلاق.
صادفت موقفًا (بالمناسبة ، نموذجي) ، عندما لا يتم تقسيم جدول كبير جدًا. في جميع نظم إدارة قواعد البيانات ، يتم تقسيم الجداول الكبيرة بشكل أفضل ، ولكن في PostgreSQL هذا صحيح بشكل خاص بسبب فراغنا المحبب. أنصح بتقسيم الجداول التي تبدأ على الأرجح بـ 100 غيغابايت. ربما يبدأ من 50. رأيت طاولات تيرابايت غير المقسمة ، وعاشوا ، على الرغم من ذلك ، على محركات أقراص الحالة الصلبة. لكن هذا كثيرًا ، سيكون من الأفضل قطعهم.

وهناك ملاحظة أخرى: يتم إلحاق المحفوظات فقط بكافة قواعد البيانات تقريبًا بحجم كبير. نادراً ما يتم العثور على البيانات المتغيرة في قواعد البيانات هذه. محدد مع ما لديك - إذا كان الأرشيف ، يمكنك بعد ذلك التفكير في كيفية نقله إلى مكان ما. وبالمناسبة ، يمكنك توفير الوصول إليها من قاعدة البيانات. ثم لا يحتاج التطبيق إلى التغيير: لن يتغير شيء له.
بعض هذه الملاحظات هي من فئة "من الأفضل أن تكون غنيًا وصحيًا من الفقراء والمرضى". في كثير من الأحيان ، أولاً ، هناك رمز قديم. ثانياً ، حدث شيء غير متوقع ، ولم يفكروا في شيء ، واتضح أن كل شيء ليس جميلًا كما نود. ولكن مع ذلك: لا تكن ذكيًا جدًا. تذكر أنك إذا كنت ذكيًا جدًا ، فمن الأرجح أنك تقوم بشيء خاطئ.
[أن تستمر.]