اختبار أداء Python ORM باستخدام طريقة TPC-C المعيارية

عند كتابة التطبيقات في Python ، غالبًا ما يتم استخدام مصممي الكائنات ذات العلاقة (ORMs) للعمل مع قواعد البيانات. أمثلة ORMs هي SQLALchemy ، PonyORM ، ومخطط ارتباط الكائنات المتضمن مع Django. عند اختيار ORM ، يلعب أدائها دورًا مهمًا إلى حد ما.


على Habr وعلى الإنترنت ككل ، من الممكن ألا تجد اختبار أداء واحد. كمثال لمعيار جودة الثعبان ORM ، يمكنك استخدام معيار Tortoise ORM ( رابط إلى المستودع ). يحلل هذا المعيار سرعة ستة ORMs لأحد عشر نوعًا مختلفًا من استعلامات SQL.


بشكل عام ، فإن معيار السلحفاة يجعل من الممكن تقييم سرعة تنفيذ الاستعلام باستخدام ORMs مختلفة ، لكني أرى مشكلة واحدة في هذا النهج للاختبار. غالبًا ما يتم استخدام ORMs في تطبيقات الويب حيث يمكن للعديد من المستخدمين إرسال طلبات مختلفة في نفس الوقت ، ولكن لم أجد معيارًا واحدًا لتقييم أداء ORM في ظل هذه الظروف. ونتيجة لذلك ، قررت كتابة المعيار الخاص بي ومقارنة PonyORM و SQLAlchemy به. كأساس ، أخذت معيار TPC-C.


تقوم شركة TPC منذ عام 1988 بتطوير الاختبارات التي تهدف إلى معالجة البيانات. لقد أصبحت منذ فترة طويلة معيارًا صناعيًا ويستخدمها جميع بائعي المعدات تقريبًا في عينات مختلفة من الأجهزة والبرامج. السمة الرئيسية لهذه الاختبارات هي أنها تهدف إلى الاختبار تحت حمولة هائلة في ظروف قريبة قدر الإمكان من تلك الحقيقية.


يحاكي TPC-C شبكة المستودعات. يتضمن مزيجًا من خمس معاملات يتم تنفيذها في وقت واحد من أنواع مختلفة وتعقيد. تتكون قاعدة البيانات من تسعة جداول مع عدد كبير من السجلات. يتم قياس الأداء في اختبار TPC-C بالمعاملات في الدقيقة.


قررت اختبار اثنين من Python ORMs (SQLALchemy و PonyORM) باستخدام طريقة اختبار TPC-C المكيفة لهذه المهمة. الغرض من الاختبار هو تقييم سرعة معالجة المعاملات عندما يصل العديد من المستخدمين الظاهريين إلى قاعدة البيانات في نفس الوقت.


وصف الاختبار


في الاختبار الذي كتبته ، يتم أولاً إنشاء قاعدة بيانات وملؤها ، وهي قاعدة بيانات لشبكة من المستودعات. مخطط قاعدة البيانات يشبه هذا :


صورة


تتكون قاعدة البيانات من ثماني علاقات:


  1. مستودع - مستودع
  2. المنطقة - منطقة المستودعات
  3. ترتيب - طلب
  4. OrderLine - سطر الأمر (بند الطلب)
  5. الأسهم - كمية منتج معين في مستودع معين
  6. البند - البند
  7. زبون - زبون
  8. التاريخ - سجل مدفوعات العملاء

, e . . , :


  1. new_order ( ) — 45%
  2. payment ( ) — 43%
  3. order_status ( ) — 4%
  4. delivery ( ) — 4%
  5. stock_level ( ) — 4%

, TPC-C.


TPC-C , , ORM, . 64+ , .


:


  1. ,
  2. . : Stock 100 000 * W, W — , : 100 * W
  3. 5 . Payment ID, . ID,
  4. NewOrder. , , Order, NewOrder. , NewOrder. , , , , , . Order bool “is_o_delivered”, False, ,

, .


New Order


  1. : id id
  2. id
  3. ()
  4. . Item.
  5. , .

Payment


  1. : id id
  2. id
  3. .
  4. 1
  5. , ,
  6. .

حالة الطلب


  1. المعاملات التي يقدمها الرقم التعريفي للعميل
  2. يتم أخذ العميل وأمره الأخير من قاعدة البيانات
  3. يتم أخذ الحالة من الطلب (تم تسليمه أم لا) وعناصر الطلب

توصيل


  1. المعاملات التي يخدمها معرف المستودع
  2. المستودع مطلوب من قاعدة البيانات برقم التعريف وجميع أقسامه
  3. لكل موقع ، يتم أخذ أقدم الطلبات التي لم يتم تسليمها. في كل واحد منهم ، تتغير حالة التسليم إلى True
  4. من قاعدة البيانات يتم أخذ المستخدمين الذين تم تسليم طلباتهم خلال هذه المعاملة ، وكل منهم يزيد من عداد التسليم

مستوى المخزون


  1. المعاملات التي يخدمها معرف المستودع
  2. المستودع مطلوب من قاعدة البيانات عن طريق المعرف
  3. يتم طلب آخر 20 طلبًا من هذا المستودع من قاعدة البيانات
  4. بالنسبة لكل عنصر من هذه الطلبات من قاعدة البيانات ، يتم طلب كمية البضائع المتبقية في المستودع

نتائج الإختبار


يشارك اثنان من ORMs في الاختبار:


  1. SQLAlchemy يتم رسم الرسوم البيانية بخط أزرق.
  2. PonyORM. يتم رسم الرسوم البيانية بواسطة الخط الأصفر.

10 2 , . multiprocessing.




PostgreSQL



, TPC-C. Pony .


صورة


:
Pony — 2543 /
SQLAlchemy — 1353.4 /


ORM . .


“New Order”


صورة


متوسط ​​السرعة:
المهر - 3349.2 trans / min
SQLAlchemy - 1415.3 trans / min


معاملة "الدفع"


صورة


متوسط ​​السرعة:
المهر - 7175.3 عبر / دقيقة
SQLAlchemy - 4110.6 عبر / دقيقة


المعاملة "حالة الطلب"


صورة


متوسط ​​السرعة:
المهر - 16645.6 trans / min
SQLAlchemy - 4820.8 trans / min


معاملة "التسليم"


صورة


متوسط ​​السرعة:
SQLAlchemy - 716.9 trans / min
Pony - 323.5 trans / min


المعاملة "مستوى المخزون"


صورة


متوسط ​​السرعة:
المهر - 677.3 عبر / دقيقة SQLAlchemy
- 167.9 عبر / دقيقة


تحليل نتائج الاختبار


بعد تلقي النتائج ، قمت بتحليل لماذا ، في حالات مختلفة ، يكون ORM أسرع من الآخر وتوصل إلى الاستنتاجات التالية:


  1. 4 5 PonyORM , , SQL PonyORM Python SQL, , SQLALchemy SQL . PonyORM:


    stocks = select(stock for stock in Stock
    if stock.warehouse == whouse
    and stock.item in items).order_by(Stock.id).for_update()

    SQLAlchemy:


    stocks = session.query(Stock).filter(
    Stock.warehouse == whouse, Stock.item.in_(items)).order_by(text("id")).with_for_update()

  2. SQLAlchemy Delivery , UPDATE, , .



, SQLAlchemy:


INFO:sqlalchemy.engine.base.Engine:UPDATE order_line SET delivery_d=%(delivery_d)s WHERE order_line.id = %(order_line_id)s
INFO:sqlalchemy.engine.base.Engine:(
{'delivery_d': datetime.datetime(2020, 4, 6, 14, 33, 6, 922281), 'order_line_id': 316},
{'delivery_d': datetime.datetime(2020, 4, 6, 14, 33, 6, 922272), 'order_line_id': 317},
{'delivery_d': datetime.datetime(2020, 4, 6, 14, 33, 6, 922261))

Pony Update:


SELECT "id", "delivery_d", "item", "amount", "order"
FROM "orderline"
WHERE "order" = %(p1)s
{'p1':911}

UPDATE "orderline"
SET "delivery_d" = %(p1)s
WHERE "id" = %(p2)s
  AND "order" = %(p3)s
{'p1':datetime.datetime(2020, 4, 7, 17, 48, 58, 585932), 'p2':5047, 'p3':911}

UPDATE "orderline"
SET "delivery_d" = %(p1)s
WHERE "id" = %(p2)s
  AND "order" = %(p3)s
{'p1':datetime.datetime(2020, 4, 7, 17, 48, 58, 585990), 'p2':5048, 'p3':911}


استنادًا إلى نتائج هذا الاختبار ، يمكنني القول أن Pony يكون أسرع كثيرًا عند الجلب من قاعدة البيانات ، ويمكن لـ SQLAlchemy في بعض الحالات إنتاج استعلامات تحديث أسرع بشكل ملحوظ.


في المستقبل ، أخطط لاختبار ORMs أخرى (Peewee ، Django) بهذه الطريقة.


المراجع


كود الاختبار: رابط مستودع
SQLAlchemy: التوثيق ، المجتمع
المهر: التوثيق ، المجتمع


All Articles