Pengujian kinerja Python ORM menggunakan metode benchmark TPC-C

Saat menulis aplikasi dengan Python, pemetaan obyek-relasional (ORM) sering digunakan untuk bekerja dengan database. Contoh ORM adalah SQLALchemy, PonyORM, dan object-relational mapper yang disertakan dengan Django. Saat memilih ORM, kinerjanya memainkan peran yang agak penting.


Di Habr, dan di Internet secara keseluruhan, dimungkinkan untuk menemukan tidak satu tes kinerja. Sebagai contoh tolok ukur ORM python berkualitas, Anda bisa menggunakan tolok ukur ORM Kura-kura ( tautan ke repositori ). Penghitungan ini menganalisis kecepatan enam ORM untuk sebelas jenis query SQL.


Secara umum, tolok ukur kura-kura memungkinkan untuk mengevaluasi kecepatan eksekusi permintaan ketika menggunakan ORM yang berbeda, tapi saya melihat satu masalah dengan pendekatan pengujian ini. ORM sering digunakan dalam aplikasi web di mana beberapa pengguna dapat mengirim permintaan yang berbeda secara bersamaan, tetapi saya belum menemukan satu tolok ukur tunggal yang mengevaluasi kinerja ORM dalam kondisi seperti itu. Sebagai akibatnya, saya memutuskan untuk menulis tolok ukur saya dan membandingkan PonyORM dan SQLAlchemy dengannya. Sebagai dasar, saya mengambil benchmark TPC-C.


TPC Perusahaan sejak tahun 1988, mengembangkan tes, yang bertujuan untuk memproses data. Mereka telah lama menjadi standar industri dan digunakan oleh hampir semua vendor peralatan pada berbagai sampel perangkat keras dan lunak. Fitur utama dari tes ini adalah bahwa tes ini ditujukan untuk pengujian di bawah beban yang sangat besar dalam kondisi sedekat mungkin dengan yang nyata.


TPC-C mensimulasikan jaringan gudang. Ini mencakup kombinasi dari lima transaksi yang dilaksanakan secara bersamaan dari berbagai jenis dan kompleksitas. Basis data terdiri dari sembilan tabel dengan sejumlah besar catatan. Kinerja dalam tes TPC-C diukur dalam transaksi per menit.


Saya memutuskan untuk menguji dua Python ORM (SQLALchemy dan PonyORM) menggunakan metode pengujian TPC-C yang disesuaikan untuk tugas ini. Tujuan dari tes ini adalah untuk mengevaluasi kecepatan pemrosesan transaksi ketika beberapa pengguna virtual mengakses database pada saat yang sama.


Deskripsi tes


Dalam tes yang saya tulis, database pertama kali dibuat dan diisi, yang merupakan database dari jaringan gudang. Skema basis data terlihat seperti ini :


gambar


Basis data terdiri dari delapan hubungan:


  1. Gudang - gudang
  2. District - area gudang
  3. Order - Order
  4. OrderLine - baris pemesanan (item pesanan)
  5. Stok - jumlah produk tertentu di gudang tertentu
  6. Barang - barang
  7. Pelanggan - pelanggan
  8. Histori - Histori pembayaran pelanggan

, 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. .

Status pemesanan


  1. Transaksi dilayani oleh id pelanggan
  2. Klien dan pesanan terakhirnya diambil dari database
  3. Status diambil dari pesanan (dikirim atau tidak) dan barang pesanan

Pengiriman


  1. Transaksi dilayani oleh id gudang
  2. Gudang diminta dari basis data oleh id dan semua bagiannya
  3. Untuk setiap situs, pesanan tertua dari yang tidak terkirim diambil. Di masing-masing, status pengiriman berubah ke True
  4. Dari database diambil pengguna yang pesanannya dikirim selama transaksi ini, dan masing-masing dari mereka meningkatkan konter pengiriman

Tingkat stok


  1. Transaksi dilayani oleh id gudang
  2. Gudang diminta dari database oleh id
  3. 20 pesanan terakhir dari gudang ini diminta dari database
  4. Untuk setiap item pesanan ini dari basis data, jumlah barang yang tersisa di gudang diminta

Hasil tes


Dua ORM terlibat dalam pengujian:


  1. SQLAlchemy Grafik digambarkan oleh garis biru.
  2. PonyORM. Grafik digambarkan oleh garis kuning.

10 2 , . multiprocessing.




PostgreSQL



, TPC-C. Pony .


gambar


:
Pony — 2543 /
SQLAlchemy — 1353.4 /


ORM . .


“New Order”


gambar


Kecepatan rata-rata:
Pony - 3349.2 trans / min
SQLAlchemy - 1415.3 trans / min


Transaksi “Pembayaran”


gambar


Kecepatan rata-rata:
Pony - 7175.3 trans / min
SQLAlchemy - 4110.6 trans / min


Transaksi "Status Pesanan"


gambar


Kecepatan rata-rata:
Pony - 16645.6 trans / min
SQLAlchemy - 4820.8 trans / min


“Pengiriman” Transaksi


gambar


Kecepatan rata-rata:
SQLAlchemy - 716.9 trans / min
Pony - 323.5 trans / min


Transaksi “Tingkat Stok”


gambar


Kecepatan rata-rata:
Pony - 677.3 trans / min
SQLAlchemy - 167.9 trans / min


Analisis Hasil Uji


Setelah menerima hasil, saya menganalisis mengapa, dalam berbagai situasi, satu ORM lebih cepat dari yang lain dan sampai pada kesimpulan berikut:


  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}


Berdasarkan hasil pengujian ini, saya dapat mengatakan bahwa Pony jauh lebih cepat ketika mengambil dari database, dan SQLAlchemy dalam beberapa kasus dapat menghasilkan permintaan Pembaruan secara signifikan lebih cepat.


Di masa depan, saya berencana untuk menguji ORM lain (Peewee, Django) dengan cara ini.


Referensi


Kode uji: Tautan repositori
SQLAlchemy: dokumentasi , komunitas
Pony: dokumentasi , komunitas


All Articles