Pythonで特定のタスクを解決するときの非自明な速度最適化

始めましょう



SQLデータベースがあります。 タスクは3つのフレーズで説明されています。



タスクの詳細


  1. スクリプトは非常に頻繁に実行する必要があります。
  2. データのアンロードでは、最も単純なクエリSELECT * FROMテーブルの結果をデータベースから減算します。 行のテーブル/ビューには、通常100000以上、列〜100があります。
  3. 検証は、rowObject.Column1 == Value(<、> ,! =)という形式の一連の条件のテストであり、より複雑なチェックです。 ポイントは、チェックには名前で列にアクセスする必要があるということです。
  4. 検査結果に関するレポートの生成。


パラグラフ1に注意してください


残りはそれほど面白くない。

例としてsqliteデータベース使用します



このようなタスクにORMを使用することは、少なくとも奇妙です。 私たちは額でそれをします(メモリを簡素化するため、結果全体をアンロードします

import sqlite3 conn = sqlite3.connect(filePath) result = tuple(row for row in conn.cursor().execute("SELECT * FROM test"))
      
      





実行後、結果にはタプルのタプルが含まれます。 属性を持つオブジェクトが必要です。

複雑な:

 ColsCount = 100 class RowWrapper(object): def __init__(self, values): self.Id = values[0] for x in xrange(ColsCount): setattr(self, "Col{0}".format(x), values[x + 1]) result = tuple(RowWrapper(row) for row in conn.cursor().execute(self.query))
      
      





ステップ2に進む準備ができましたか? そして、両方の例の速度を測定してみましょう(完全なテストコードはこちら )。

100,000行、101列

私は数秒でそれをしました:

サンプル1:4.64823588605

サンプル2:17.1091031498

クラスインスタンスの作成には10秒以上かかります

私の中のC ++プログラマーは、それについて何かをしたかったのです。



解決策がありました


collectionsモジュールのnamedtupleを使用します。 ここでは、その動作の原理について詳しく説明しません。 必要な機能を示す小さな例を示します。

 import collections columns = ('name', 'age', 'story') values = ('john', '99', '...blahblah...') SuperMan = collections.namedtuple('SuperMan', columns) firstSuperMan = SuperMan._make(values) print(firstSuperMan.name) print(firstSuperMan.age) print(firstSuperMan.story)
      
      





そして今、タスクのコンテキストでの例:

 import collections columns = tuple(itertools.chain(('Id',), tuple("Col{0}".format(x) for x in xrange(ColsCount)))) TupleClass = collections.namedtuple("TupleClass", Columns) result = tuple(TupleClass._make(row) for row in conn.cursor().execute(self.query))
      
      





速度を測定します。

サンプル1:4.30456730876

サンプル2:15.3314512807

サンプル3:4.67008026138



まったく別の問題。 ここでベースの作成と速度の測定に関する完全なコード例を参照してください



たとえば、使用された記事






All Articles