قبل بضعة أسابيع من
مهرجان الالتزام المهم - الأخير قبل إصدار
feature freeze
من
PostgreSQL 11 - شاهدت النشرات الإخبارية
للمتسللين ، التي تضغط مجموعة الشرائح في الحزمة اليسرى ، فيلم
MERGE . حاول مدير الإثارة والرئيس التنفيذي لشركة
2ndQuadrant ، Simon Riggs ، دفع رقعة تنفذ بناء جملة أمر MERGE
بمثابرة وإبداع مثير للإعجاب. كان ريجز ممثلًا كوميديًا منذ عام 2009 ، ومع وضع الممثل الكوميدي يمكنك الموافقة على التصحيحات بنفسك. وقد عارضته لجان PostgreSQL والمحاربين القدماء الأقل احترامًا. كانت العواطف تغلي بشكل واضح وضمني ، لم تصل حتى إلى الإهانات المباشرة - وهي حقيقة مفاجئة للنظامي في العديد من المنتديات المحلية. ومع ذلك ، بقي بعض التوتر حتى الآن عندما تمت تسوية السؤال ، وليس هناك ما يجادل حوله.
لكن العواطف هي عواطف (سيتم مناقشتها بشكل أكبر) ، وأود أن أفرز جوهر هذه المشكلة بعيدة المنال.

دمج خارج
إذا كان الأمر بسيطًا تمامًا ، فإن الشيء هو هذا: لدينا جدولان لهما نفس الحقول وبيانات مختلفة. افترض الاسم والعمر. نحن بحاجة إلى دمجها في واحد. ولكن سيكون من الضروري تحديد ما يجب فعله بتلك الشخصيات الموجودة في كلا الجدولين. على الأرجح سنريد كل شيء في الجدول النهائي ، وتحديث المعلومات لتتناسب مع الأفراد. من الواضح أنه حتى في هذا الإعداد ، تعد هذه مهمة شائعة جدًا. يمكن حلها بدون
MERGE
، مما يجعل الطلب المعقد ، يمكنك استخدام المشغلات وما إلى ذلك. لكن هذا غير مريح. ومع ذلك ، فإن الإصدار غير القانوني من MERGE ، والذي يسمى UPSERT (UPdate + inSERT) ، يحل هذه المشكلة.
عامل MERGE موجود في معيار SQL-2003 وهو بالفعل في كل مجده في SQL-2008. يتم تنفيذه في Oracle و DB2 و MS SQL ، مما يعني أن عدم وجود MERGE سيزعج أولئك الذين يفكرون في الانتقال من DBMSs إلى PostgreSQL. كانت رغبة سيمون ريجز الشوق في أسرع وقت ممكن ، بالفعل في PostgreSQL 11 ، مدفوعة برغبات عملاء 2ndQurant ، وليس بالطموح أو الشجار.
في الواقع ، تتمتع MERGE بقدرات غنية ، ولا يجب أخذ البيانات من الجداول ، خاصة من تلك المماثلة في الهيكل.
بناء جملة الأمر كما يلي:
MERGE INTO tablename USING table_reference ON (condition) WHEN MATCHED THEN UPDATE SET column1 = value1 [, column2 = value2 ...] WHEN NOT MATCHED THEN INSERT (column1 [, column2 ...]) VALUES (value1 [, value2 ...]);
ومع ذلك ، يمكنك مثل هذا:
MERGE [hint] INTO [schema .] {table | view} [table_alias] USING { subquery | [schema .] { table | view}} [table_alias] ON ( condition ) [ merge_update_clause ] [ merge_insert_clause ] [ error_logging_clause ] ;
يتم تنفيذ بناء الجملة هذا في Oracle. بالكلمات ، تقوم MERGE بتنفيذ الإجراءات التي تعدل السجلات في الجدول الهدف target_table_name باستخدام data_source في أمر SQL واحد ، والذي يمكن ، وفقًا للشروط ، إجراء INSERT أو UPDATE أو DELETE فيما يتعلق بالسجلات في target_table_name. في هذه الحالة ، يمكن أن يكون target_table_name طريقة عرض ، ويمكن أن يكون مصدر_البيانات مجموعة من
الجداول أو طرق العرض ، نتيجة استعلام فرعي .
أولاً ، ينفذ
MERGE
صلة
left outer join
على
data_source
مع
target_table_name
، مما يشير إلى 0 أو أكثر من سجلات تغيير المرشح ؛
WHEN
تحسب البنود بالترتيب المحدد ؛ بمجرد استيفاء الشرط ، يتم تنفيذ الإجراء المقابل. الكلمات الرئيسية
WHEN [NOT] MATCH THEN
ليست شائعة جدًا في
SQL
، لذلك نذكرك أن هذا هو عنصر تحكم مثل
if-else
بلغات أخرى. يعمل
MERGE
بالطريقة نفسها التي يعمل بها
UPDATE, INSERT
أو
UPDATE, INSERT
أو
DELETE
فيما يتعلق
target_table_name
، إلا أن بناء الجملة للأمر بأكمله يختلف.
يجب أن يقوم بند مع
ON
بإجراء اتصال على جميع أعمدة المفتاح الأساسي أو ، إذا تم تحديد أعمدة أخرى ، فيجب استخدام بعض الفهرس الفريد بحيث تحدد
[NOT] MATCHED
الفور إجراءات سجل المرشح من أجل استبعاد التفاعل مع المعاملات الأخرى.
أمر
MERGE
الحتمية: لا يمكنك تحديث نفس السجل عدة مرات في نفس أمر MERGE.
مثال:
MERGE CustomerAccount CA USING RecentTransactions T ON T.CustomerId = CA.CustomerId WHEN MATCHED THEN UPDATE SET Balance = Balance + TransactionValue WHEN NOT MATCHED THEN INSERT (CustomerId, Balance) VALUES (T.CustomerId, T.TransactionValue);
أو مع استعلام فرعي:
MERGE INTO bonuses D USING (SELECT employee_id, salary, department_id FROM employees WHERE department_id = 80) S ON (D.employee_id = S.employee_id) WHEN MATCHED THEN UPDATE SET D.bonus = D.bonus + S.salary*.01 DELETE WHERE (S.salary > 8000) WHEN NOT MATCHED THEN INSERT (D.employee_id, D.bonus) VALUES (S.employee_id, S.salary*.01) WHERE (S.salary <= 8000);
في
IBM DB2 ، ستعمل الصيغة أيضًا.
كما يقولون ، "تحت غطاء محرك السيارة" سيتم ذلك بشكل مماثل
UPDATE FROM
البناء.
منذ عام 2008 ، لدى
MS SQL أيضًا MERGE
.
ولكن حتى وراء بناء جملة معياري واحد ، تبدأ مشكلة الاختيار من بين عدد كبير من الآليات وأساليب التنفيذ. يجب أن يعمل الفريق على مستويات مختلفة من عزل المعاملات ، مع خوارزميات قفل مختلفة ، مع التركيز على وضع التشغيل التنافسي للغاية أو غير ذلك. وكما قد تتوقع ، من أجل تطبيق هذا المنطق المعقد ، تحتاج إلى لمس الكثير من مكونات DBMS.
UPSERT ، زائفة الاندماج
من الواضح أن مطوري DBMS كانوا يبحثون عن حلول وسط ، يرفضون إعادة إنتاج بناء الجملة القياسي. زائد هذا النهج هو الحرية. يمكنك استخدام الآليات العضوية لنظام DBMS معين ، ويمكنك تحسين التنفيذ للمهام التي تعتبرها الأكثر صلة بمستخدميك.
على سبيل المثال ، في
MySQL يوجد أمر
REPLACE
يعمل
INSERT
، ولكن إذا كانت الصفوف الجديدة والقديمة لها نفس القيم في
PRIMARY KEY
أو الفهرس
UNIQUE
، فسيتم قتل الصف القديم قبل إدراج الصف الجديد. ولكن هناك أيضًا
INSERT ... ON DUPLICATE KEY UPDATE
حيث تحدث
INSERT
و
UPDATE
(بدلاً من
DELETE
في
REPLACE
). هذا هو
UPSERT
.
وهناك INSERT IGNORE
، الذي لا يقوم ببساطة بعملية الإدراج ، دون إلقاء خطأ (ولكن تحذير) تحت قيود معينة على الجدول الهدف.
سجلات PG MERGE
في مجتمع PostgreSQL ، بدأ الحديث عن MERGE في عام 2005 عندما سأل Jaime Casanova عما
إذا كان أي شخص في المجتمع قد بدأ في تطوير MERGE
.
اقترح Peter Eisentraut مناقشة ما إذا كان يجب على PostgreSQL تطوير أحد خيارات MERGE: على غرار تطبيق MySQL ، أو من الأفضل توجيه الجهد إلى نسخة خفيفة الوزن وظيفية من نوع MERGE
من Oracle. ومع ذلك ، هل يستحق الأمر بذل جهود في هذا الاتجاه؟في منتصف مناقشة قصيرة ، يظهر بطل هذه الرواية
سيمون ريجز مع الكلمات:
يعد MERGE مفيدًا لكل من أنظمة OLTP و DW (مستودع البيانات - مستودعات البيانات ، أي التطبيقات التحليلية حيث نادرًا ما يتم تحديث الاستعلامات المعقدة ، ولكن ليس البيئات والبيانات التنافسية للغاية ، وإذا تم تحديثها ، فعادة ما تكون في أجزاء كبيرة. <...> يمكننا تنفيذ MERGE كمتغير من COPY FROM ، سيكون رائعًا جدًا.يتفق الجميع: نعم ، رائع. بتعبير أدق ، كل شيء تقريبًا:
ستيفن فروست :
أعتقد أنني لست الوحيد الذي يقول إنني بحاجة إلى معيار MERGE كامل ومتوافق.لدى بروس مومجيان اقتراح مختلف وأكثر واقعية:
يبدو لي أننا بحاجة إلى تنفيذ بعض الخيارات التي يمكننا تنفيذها في MERGE
، وفي الباقي سنقدم خطأ (وفي الحالات التي يكون فيها من الضروري حظر الجدول بأكمله). وبعد أن نحصل على تعليقات من المستخدمين وسنفكر في ما يجب القيام به بعد ذلك.ولكن حتى الآن لم يحدث شيء.
لقد كسر الجليد
في عام
2008 ، دعا
Simon Riggs مرة أخرى للتعامل مع MERGE - أي من الطرق للاختيار (بحلول ذلك الوقت ظهرت نسخة جديدة من MERGE في معيار SQL-2008 بالفعل ، حتى الآن كمسودة). يرسم بالتفصيل الحالي في ذلك الوقت تنفيذ Oracle و IBM و MS SQL وبناء الجملة من MySQL و Teradata. وبعد ذلك بقليل ذكر بالفعل
بداية العمل في الربع الثاني في هذا الاتجاه.
يكتب بيتر إيزينتراوت
على مدونته :
بالطبع ، ريجز هو أحد أكثر المتخصصين المؤهلين ، يمكنه قيادة العمل على تنفيذ MERGE.ولكن هنا يأتي أول منعطف غير متوقع: يشارك
الطالب في المشكلة - مشارك في تطوير برنامج
GSoC ، أي Google Summer of Code. اسمه
Boxuan Bxzhai - لا أفترض أن
أنسخ الاسم الأخير. سرعان ما يكتب أن العمل على وشك الانتهاء.
ولكن تقريبا لا يحسب. يكتب
جريج سميث من 2ndQuadrant (أي سيمون ريجز حليف):
لذا ، لدينا تصحيح في الكود يحتوي على نصف دزينة من المشاكل الخطيرة التي لم يتم حلها. أنا صامت عن هؤلاء الصغار. المشاكل عميقة للغاية بحيث لا يمكن وضع اللمسات الأخيرة على التعليمات البرمجية للالتزام. وفي الوقت نفسه ، لم يسمع أي شيء من Boxuan لفترة طويلة. يمكننا مساعدته ، ولكن أين هو؟ من يعرف؟تشتعل مناقشة مسارات التنفيذ مرة أخرى في عام
2014 ، ولكن مرة أخرى لا يحدث شيء: لا يوجد رمز.
أخيرًا ، في وقت مبكر من عام
2017 ، كتب
سيمون ريجز :
أنا أعمل على رمز لإلزام MERGE
بالإصدار 11 من PostgreSQL . نحن نستخدم نفس الآليات التي تكمن وراء INSERT ON CONFLICT
التي تعمل بالفعل ، بحيث لا تكون هناك حاجة إلى تغييرات في البنية التحتية ، فقط في الأساس تنفيذ بناء الجملة فوق ما هو متاح. لكنني أكتب الرمز الخاص بي من البداية ، ولا أستخدم التطورات السابقة.نحن نتحدث عن Peter Geoghegan (
VMware ) الذي تم تنفيذه في ذلك الوقت بالفعل في 9.5 صيغة بديلة
INSERT .. ON CONFLICT UPDATE
، تختلف عن معيار SQL ، ولكنها لا تزال مرتبطة بـ
MERGE
و
REPLACE
في MySQL.
في البداية ، قوبل عمل سيمون بعلامات تعجب من عمل نيس! ومع ذلك ،
روبرت هاس ، على الرغم من دعمه ، يحذر من شذوذ التسلسل المحتمل. على سبيل المثال ، للتعامل مع
INSERT .. ON CONFLICT UPDATE
، بدون دمج في قاعدته ، يكون أكثر هدوءًا إلى حد ما.
UPSERT
مؤلف PostgreSQL
UPSERT
نفسه:
لن أخلط MERGE
ON CONFLICT DO UPDATE
و MERGE
. <...> لتحميل أجزاء كبيرة من البيانات (تحميل ضخم) ، على سبيل المثال ، استخدم خوارزمية merge join
. <...> بشكل عام ، ترتبط مزايا MERGE
بحقيقة أن الاتصالات العادية ستعمل هناك بالطريقة المعتادة: nested loop, hash, merge
. وفي INSERT … ON CONFLICT
لا توجد صلات على الإطلاق.هاس:
مثل بيتر ، أعتقد أنه إذا تم ذلك بهذه الطريقة ، فإن مثل هذا القفل القوي عند تنفيذ طلب DML
يبدو هكذا. من غير المحتمل أن يكون أي شخص مسرورًا لأن شخصًا واحدًا فقط يمكنه العمل مع MERGE
في وقت واحد.للفضول: يقوم Geigan بتفكيك التفاصيل الدقيقة والاختلافات
UPSERT
بين
MERGE
و
MERGE
هنا وهنا (نقوم بتخزين
المراسلات المؤرشفة لـ PostgreSQL على موقعنا على الإنترنت).
سيمون يقاوم. يناشد التاريخ الحديث. على سبيل المثال ، حول التقسيم قالوا أيضًا "بناء جديد ، لا شيء أكثر." لكن اتضح أن هذا شيء مفيد للغاية.
لكنني لا أقترح أن أدرك على الفور كل ما هو في MERGE. سنفعل الشيء نفسه كما هو الحال مع التقسيم - نقسم التطوير إلى مراحل.وحجة أخرى ، في رأيي مقنعة للغاية:
جيد. لكن دعنا نختار. أقترح خيارا عمليا. ستأتي 10 سنوات قريبًا من أول محاولة جادة لتطوير MERGE
. ألم يحن الوقت للبدء في فعل شيء ما ، والحصول على بعض الحلول المفيدة ، بدلاً من الانتظار لمدة 10 سنوات أخرى من الحل المثالي؟ بافتراض وجوده على الإطلاق.أخيرًا ، يصل التصحيح إلى المجتمع. ما التاريخ؟ تخيل لو سمحت. لا ، لم يخمنوا: أرسله سايمون في 30 ديسمبر 2017. وينص على أن هذا هو التصحيح WIP ، أي العمل قيد التقدم - التصحيح في العمل.
سيمون ، يناير:
تم الانتهاء من التصحيح دون أي أخطاء خاصة. 1200 سطر من التعليمات البرمجية بالإضافة إلى الاختبارات والتوثيق. سوف أقوم بإلزامه بهذه المسابقة ، وسنكمل RLS (حماية مستوى الصف - الحماية على مستوى التسجيل) وتقسيم الدعم لاحقًا.مجالس اللجان
هنا علينا أن نتخذ خطوة جانبا وشرح دور المفوض في المجتمع. لقد تغيرت وظائف المفوض ، أي الشخص المفوض بقبول التصحيح في الإصدار التالي ، تاريخياً. ذات مرة ، عندما كان هناك عدد قليل من المطورين ، تم توزيع الحق في الالتزام بسخاء. على سبيل المثال ، حصل
جوليان أسانج الشهير (في مجال مختلف تمامًا) على لقب القائد ، كونه مؤلف ست بقع فقط. الآن ليس من السهل أن تصبح مفوضًا ، لا توجد شركات ناشئة على قائمة عشرات الأشخاص. Boyus Momdjan (
EnterpriseDB ) لديه 13363 التزامًا ، Tom Lane (Tom Lane ، Crunchy
Data ) 13127 ، روبرت Haas (
EnterpriseDB ) - 2074. وبالمناسبة ، فإن اللاعب
الوحيد من روسيا هو
Fedor Sigaev (Teodor Sigaev ،
Postgres Professional ) مع التزاماته 383 . سيمون ريجز نفسه لديه 449 منهم ، وأكرر: إنه بصفته مفوضًا ، لديه ما يكفي من السلطة لأخذ التصحيحات والالتزام بها - موظفيه وموظفيه. شيء آخر هو أنه لا يستحق القيام بذلك ، وتجاهل بصراحة آراء اللجان البارزة الأخرى. يمكنهم أيضًا حرمان مركز المفوض ، ولكن على الأقل
revert
التصحيح.
كسر في المعركة
بالطبع ، في التصحيح "ميؤوس منه" ، بشكل عام ، على عجل ، وجدوا أخطاء جديدة. لفة الإصدارات الجديدة ردا على ذلك.
في نهاية يناير ، تظهر شخصية جديدة: مطور 2ndQuadrant
Pavan (اسمه الجميع بالاسم ؛ Pavan Deolasee تمامًا). يتعامل المجتمع الآن مع ترادف: يرسل بافان إصدارات جديدة ويشكر على النقد ، ويكسرها سايمون بضغط تسويقي ملحوظ.
هاس:
لا أعتقد أن الأمر يستحق اتخاذ قرارات أحادية الجانب بشأن استبعاد الميزات التي تعمل في كل مكان. إذا اتفقنا على أن بعض الميزات لن يتم تضمينها في هذا التصحيح - فهذا شيء واحد. ويختلف الأمر تمامًا أنه في التعليقات بهذه المناسبة عبر الجميع عن عدم اتفاقهم. ولم نسمع في الواقع أسباب استبعاد هذه الميزات.تم تقديم المنطق على النحو التالي:
- بداهة ، هناك مشاكل خطيرة لأنها لا يمكن إلا أن تكون في التطورات في أسلوب "هجوم الفرسان".
- يمكن إكمال دعم الميزات الهامة مثل التقسيم الجديد في الإصدارات 10-11 أو CTE (تعابير الجدول الشائعة = مع استعلامات) أو RLS (أمان مستوى الصف) حتى بعد قبول التصحيح في الإصدار الحالي ، ولكن فقط إذا كانت البنية المقترحة مناسبة للبناء في الأعلى وظيفتها المطلوبة.
يصور بيتر جيجان الثاني هذا:
عادة ما أركز على دعم الوظائف المختلفة ، لأنه إذا كان كذلك ، فإنه يعزز الاعتقاد العام بأن التصميم مصنوع كما ينبغي . وإذا كانت مثل هذه المشاكل ناتجة عن دعم تعبيرات WITH
[أي CTE
] ، فإنني أفهم أن البنية التحتية الأساسية ستسبب مشاكل هنا وهناك.في هذه الأثناء ، تقترب الساعة X (آخر اجتماع للجنة) ، وتتجمع الغيوم فوق MERGE. ليس الأمر أن الآباء المؤسسين بحثوا على وجه التحديد عن مشاكل خطيرة في هندسة الرقع التي صنعها سيمون ثم بافان. لم يكن عليّ البحث عن المشاكل ؛ لقد فتحوا أنفسهم طواعية.
الخاتمة تقترب
المؤامرة تتسارع. على الرغم من الموقف الرائع للجان الأخرى تجاه تعهده ،
في 2 أبريل ، قرر سيمون تنفيذ
الأمر التالي لـ SQL: تصحيح
2016 ، يضيف الملفات ، يدير ديبيز (Hubert Lubachevsky)
الإعلان عنه على مدونته ، ولكن في نفس اليوم يقوم سيمون بإرجاع كل شيء إلى الوراء لأنه الأخطاء.
في اليوم التالي ، التزم مرة أخرى بإضافة دعم.
رداً على ذلك ، فإن الادعاءات خطيرة حقاً.
كتب أندريس فرويند (
EnterpriseDB ):
لم تبهرني هندسة MERGE في المحلل اللغوي والمنفذ بشكل موثوق. إنشاء صلات مخفية أثناء تحليل التحليل فكرة سيئة حقًا. يجب تغيير بنية المنفذ بالكامل.توم لين:
تصميم شجرة التحليل ضعيف.تفرط في تحميل وظيفة InsertStmt
، InsertStmt
، أنها لا تقوم InsertStmt
على الإطلاق ، ولكنها تحتوي بشكل عشوائي على نفس الحقول مثل الحقل الأصلي. وليس كل شيء ، ولكن البعض. هذا أمر سيئ ، يؤدي إلى الارتباك.دعونا نضيف ملاحظات
فيدور سيغاييف :
في المحلل اللغوي ، ظهرت عُقد INSERT
ذات الصلة بـ MERGE
، مُعلَّقة بمجموعة من الحقول الإضافية. إذا نظرت إلى خطة التنفيذ في ANALIZE
، فلن تفهم على الفور ما إذا كنت تتعامل مع INSERT
عادي أو مع MERGE
: لفهم ، تحتاج إلى النظر في حقول إضافية.سايمون ، بهدوء:
حسنًا ، سنغير ذلك وسنرسل ملفًا جديدًا غدًا .
هاس:
أتفق مع بيتر. اختيار العمارة غير ناجح.سايمون لا يستسلم.
6 أبريل ، ردا على انتقاد توم لين ، يرتكب رقعة جديدة بصيغتها المعدلة في المحلل.
التفاوض والاستسلام
بروس مومجان
6 أبريل :
أريد أن أشير إلى أن الناس لم يطلبوا منك العمل بجد لإصلاح شيء على وجه السرعة. طلبوا منك سحب التصحيح. يمكنك بالطبع العمل بجد على أمل أن يغيروا رأيهم ، ولكن - مرة أخرى - لم يسألوك عن ذلك.سايمون:
إذا كان توم [لين] وأندريس [فروند] للأيام القليلة المتبقية لا يزالان يشعران بأن مخاوفهما لم تبدد ، فسأكون سعيدًا بإعادة التصحيح دون مزيد من اللغط.توم لين:
ما زلت أصوت من أجل إعادة التصحيح. حتى لو كان مثاليًا الآن ، ليس لدى الناس الآن الوقت لإقناعهم بذلك - إلى حلق الأمور الملحة الأخرى.هذا كل شيء.
قال سيمون حسنًا ،
MERGE
المعركة في
MERGE
. تم ضخ كل التصحيحات مرة أخرى ، وتم نقل الموضوع إلى المجموعة التالية بالحالة "في انتظار الانتهاء من المؤلف". صنع المشاركون في العرض السلام.

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