## アプリケーションをデータベースと一緒に使用する必要がある場合、Python プログラミングでは通常、オブジェクト リレーションシップ マッパー (ORM) が使用されます。 Python ORM の例としては、SQLAlchemy、Peewee、Pony-ORM、Django などがあります。 ORM パフォーマンスの選択は重要な役割を果たします。しかし、これらのツールセットはどのように比較されるのでしょうか? ORM パフォーマンス ベンチマークは明確な尺度を提供しますが、改善の余地はまだたくさんあります。困っている開発者を支援するために、定性的な ORM ベンチマークを調査して拡張しました。定性的な Python ORM ベンチマーク Tortoise ORM (リポジトリへのリンク) は、11 種類の SQL クエリに対する 6 つの ORM の速度を分析します。
関連する学習の推奨事項: Python ビデオ チュートリアル
通常、Tortoise ベンチマークはさまざまな ORM のクエリ実行速度を評価できます。ただし、このテスト方法には欠陥があります。ほとんどの ORM は Web アプリケーション用に選択されています。この場合、複数のユーザーがあらゆる種類のクエリをデータベースに送信することがよくあります。この文脈で Python ORM のパフォーマンスを評価できるベンチマーク ツールが存在しないため、独自の PonyORM と SQLAlchemy を作成して比較することにしました。基礎として、TPC-C ベンチマークを使用しました。
1988 年以来、TPC はデータ処理の分野で開発とテストを行ってきました。これらはずっと前に業界標準となり、ほぼすべてのデバイス ベンダーがさまざまなハードウェアおよびソフトウェア サンプルでそれらを使用しています。これらのテストの主な特徴は、実際の条件にできるだけ近い大きな負荷の下でのテストに焦点を当てていることです。
TPC-Cは倉庫ネットワークをシミュレートします。これは、同時に実行されるさまざまなタイプと複雑さの 5 つのトランザクションの組み合わせで構成されます。このテストの目的は、複数の仮想ユーザーがデータベースに同時にアクセスする場合のトランザクション処理の速度を評価することです。
このタスクに適した TPC-C テスト方法を使用して、2 つの Python ORM (SQLALchemy と PonyORM) をテストすることにしました。このテストの目的は、複数の仮想ユーザーがデータベースに同時にアクセスする場合のトランザクション処理の速度を評価することです。
テスト手順
最初のステップは、ウェアハウス ネットワークのデータベースを作成してデータを取り込むことです。
データベースには 8 つの関係が含まれています。
1. 倉庫
2. 地区
3. 注文
4. 注文明細
5. Stock
6. Project
7. Customer
8. History
Pony と SQLAlchemy のデータベースは同じです。主キーと外部キーのみがインデックス付けされます。 Little A はこれらのインデックスを自動的に作成します。 SQLAlchemy では手動で作成しました。
テスト中、複数の仮想ユーザーがさまざまな種類のトランザクションをデータベースに送信しました。各トランザクションには複数のリクエストが含まれます。発生確率の異なる処理のために送信されるトランザクションは合計 5 種類あります。
トランザクション:
1. 新規注文 - 45%
2. 支払い - 43 %
3. order_status-4%
4. Delivery-4%
5. Stock level-4%
トランザクション発生の可能性とオリジナルの TPC - C テストと同じ。
ただし、技術的な制限のため、また次のプロセッサのパフォーマンスをテストしたかったため、元のテストは 64 GB 以上の RAM を搭載したサーバーで実行されたことに注意してください (多くのプロセッサとプロセッサが必要です)。巨大なディスク容量)TPC-C テスト。巨大な負荷に耐えるハードウェアの能力ではなく、ORM が重要であるため、このテストは多少簡略化されています。
TPC-C テストとの主な違いは次のとおりです。
主な違い:
1. このテストでは、元のテストよりも少ない仮想ユーザーが実行されます
2 . 私のテストではテーブル エントリが少なくなりました。例: 元のテストの「在庫」関係のエントリ数は、100,000 * W (W は倉庫の数) という式を使用して計算されました。このテストでは 100*W です。
3. TPC-C では、一部のトランザクションには、データベースからデータをクエリするための複数のオプションがあります。たとえば、支払いトランザクションでは、データベースから ID で顧客をリクエストする可能性と、姓と名でデータベースにリクエストする可能性があります。現在、私のテストは ID による呼び出しのみを行っています。
4. 私のテスト データベースには、TPC-C よりもテーブルが 1 つ少ないです。 TPC-C テストでは、注文が作成された後、注文は Order テーブルと NewOrder テーブルに追加されます。注文が配送されると、NewOrder テーブルから削除されます。これにより、1 分あたり大量のトランザクションを適用する場合に速度が向上しますが、データベースにアクセスするユーザーが少ないため、これは必要ありません。代わりに、Order テーブルに、注文が配達されるまで False となるブール属性「is_o_delivered」を追加しました。
次に、各トランザクションの役割について簡単に説明します。
トランザクション数
新しいコマンド
1. 2 つのパラメーターをトランザクションに渡します: ウェアハウス ID と顧客 ID
2. から渡された ID を使用します。データベースから倉庫と顧客を選択します
# 3. データベースから倉庫エリアをランダムに選択します# 4. 注文明細行の数を示す乱数を生成します。
5. Order オブジェクトを作成します
6. ループして OrderLine オブジェクトを作成します。ループの各反復で、アイテム テーブルからランダムなアイテムを選択します
7. 注文内の各アイテムの在庫を変更します
支払い
1. 2 つを変更します。トランザクションに渡されるパラメータ: 倉庫 ID と顧客 ID
2. 渡された ID によってデータベースから倉庫と顧客を選択します
3. データベースから倉庫エリアをランダムに選択します
4. 支払金額を示す乱数を生成します
## 5. 倉庫と地域の残高を支払金額分増加させます6. 顧客残高により支払金額を減少させます
7. 顧客支払いカウンターを増やす
# 8. 顧客支払い金額の合計を増やす# 9. 履歴オブジェクトを作成する
# 注文ステータス 1. 顧客 ID をトランザクション パラメータとして渡します。# 2. ID と顧客の最後の注文で顧客を選択します。
# 3. 注文から注文ステータスと注文明細を取得します。 Delivery 1. 倉庫 ID をトランザクション パラメータとして渡します 2. データベースから倉庫とそのすべてのエリアを選択します 3. それぞれについて地域では最も古い未配達の注文が選択されます。 4. 配送ステータスが True に変更される各注文について # 5. 注文数量が増加する各顧客について # 在庫レベル # 1.トランザクション パラメータとして倉庫 ID を指定します。 2. ID でデータベースから倉庫を選択します。# 3. 倉庫の最後の 20 件の注文を選択します。
# 4. 注文の場合各プロジェクトでは、プロジェクトの在庫レベルを評価します。 テスト結果 テストには 2 つの ORM が参加しています: 1. SQLAlchemy (グラフ上の青い線)2. PonyORM (グラフ上のオレンジ色の線) 以下は、2 つの並列プロセスでデータベースにアクセスし、10 分間テストを実行した結果です。 Multiprocessing モジュールを使用してプロセスを開始します。 まず、TPC-C テストで予想どおり 5 つのトランザクションすべてをテストしました。このテストの結果、Little A の速度は以前の約 2 倍になっています。 平均速度: · 小規模 A-2543 トランザクション/分 · SQLAlchemy-1353.4 トランザクション/分 その後、 5 つのトランザクションを個別にトランザクション ORM パフォーマンス。以下は各取引の結果です。 新しいコマンド 平均速度: · 小規模 A-3349.2 トランザクション/分 · SQLAlchemy-1415.3 トランザクション/分支払い 平均速度: · 小規模 A-7175.3 トランザクション/分 · SQLAlchemy-4110.6 トランザクション/分 注文ステータス 平均速度: · 小規模 A-16645.6 トランザクション/分 · SQLAlchemy-4820.8 トランザクション/分 配信 平均速度:
· SQLAlchemy-716.9 トランザクション/分 · Small A-323.5 トランザクション/分 インベントリ レベル 平均速度: · Small A -677.3 トランザクション/分 · SQLAlchemy-167.9 トランザクション/分 テスト結果の分析 結果を受け取った後、なぜこれが起こったのかを分析し、次の結論に達しました。 SQL コードを生成するときに PonyORM が Python 式を SQL に変換した結果を記憶しているため、5 つのトランザクションのうち 4 つで PonyORM の方が高速です。したがって、Pony はクエリが繰り返されるときに式を再度変換しませんが、SQLAlchemy はクエリを実行する必要があるたびに SQL コードを生成する必要があります。 Pony でのこのようなクエリの例:
stocks = select(stock for stock in Stock if stock.warehouse == whouse and stock.item in items).order_by(Stock.id).for_update()生成された SQL:
SELECT “stock”.”id”, “stock”.”warehouse”, “stock”.”item”, “stock”.”quantity”, “stock”.”ytd”, “stock”.”order_cnt”, “stock”.”remote_cnt”, “stock”.”data”FROM “stock” “stock”WHERE “stock”.”warehouse” = %(p1)s AND “stock”.”item” IN (%(p2)s, %(p3)s)ORDER BY “stock”.”id”FOR UPDATE {‘p1’:7, ‘p2’:7, ‘p3’:37} SQLAlchemy: stocks = session.query(Stock).filter( Stock.warehouse == whouse, Stock.item.in_( items)).order_by(text(“id”)).with_for_update()生成された SQL:
SELECT stock.id AS stock_id, stock.warehouse_id AS stock_warehouse_id, stock.item_id AS stock_item_id, stock.quantity AS stock_quantity, stock.ytd AS stock_ytd, stock.order_cnt AS stock_order_cnt, stock.remote_cnt AS stock_remote_cnt, stock.data AS stock_dataFROM stockWHERE stock.warehouse_id = %(warehouse_id_1)s AND stock.item_id IN (%(item_id_1)s, %(item_id_2)s) ORDER BY id FOR UPDATE {‘warehouse_id_1’: 7, ‘item_id_1’: 53, ‘item_id_2’: 54}ただし、明らかに SQLAlchemy の方が高速である可能性があります。異なるオブジェクトに適用される複数の UPDATE 操作を 1 つのコマンドに結合できるため、配信タイプのトランザクションの実行が容易になります。 例:
INFO:www.zpedu.com/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))この場合、Little A は更新ごとに個別のクエリを送信します。 結論 テスト結果に基づくと、Pony はデータベースからの選択が高速であると言えます。一方、場合によっては、SQLAlchemy の方が Update 型のクエリを高速に生成できます。
以上がTPC-Cベンチマークに基づくPython ORMのパフォーマンステストの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。