0

データベースの設計は最適とはほど遠いですが、それに対処しなければならず、今は本当に行き詰まっています。

編集:私は使用していますcx_Oracle

これは私のクエリです:

query="select degree, spectraldev.event.eventnumber \
       from spectraldev.degree \
       join spectraldev.alignment on \
            (spectraldev.version_id = alignment.version_id) \
       join spectraldev.event on \
            (alignment.timestamp between event.eventstart and event.eventstop) \
       join spectraldev.eventsetup on \
            (spectraldev.event.eventsetup = spectraldev.eventsetup.oid) \
       where spectraldev.event.eventnumber>=" + options.start + " AND spectraldev.event.eventnumber<=" + options.stop + " AND \
            HITS>=" + str(options.minimum_hits)+" \
       order by spectraldev.event.eventnumber"

db_cursor.execute(query)

これは、一意の番号 ( 346554degreeなど) で識別される多くのイベントに対して一連の s (12.34 など)を返します。eventnumber

だから私はこのようなテーブルを取得します:

454544    45.2
454544    12.56
454544    41.1
454544    45.4
454600    22.3
454600    24.13
454600    21.32
454600    22.53
454600    54.51
454600    33.87
454610    32.7
454610    12.99

など…</p>

ここで、各イベントの平均度を含む辞書を作成する必要があります(対応するすべてのフロートを合計し、それらの数で割った値)。

これはSQLで実行できると思いますが、うまくいきません。現時点ではこれを行うために python を使用していますが、約 1000000 のイベントを処理する必要があるため、フェッチ コマンドは約 2000 のイベントを完了するのに 1 ~ 2 時間かかります。

これは私の取得部分であり、非常に時間がかかります。

_degrees = []
for degree, eventNumber in cursor.fetchall():
    _degrees.append([eventNumber, degree])

次に、並べ替え(これは非常に高速で、1秒未満)と平均の計算(これも非常に高速です):

_d={}
for eventNumber, degree in _degrees:
    _d.setdefault(eventNumber, []).append(degree)

for event in events:
    _curDegree = _degrees[int(event)]
    _meanDegree = sum(_curDegree) / float(len(_curDegree))
    meanDegrees.append(_meanDegree)

SQL で Python の部分を実行する方法はありますか?

4

1 に答える 1

1

これは余談ですが、重要なことです。あなたはSQLインジェクションに対して無防備です。特定のインスタンスでは問題にならないかもしれませんが、常に最悪の事態に備えてコーディングすることをお勧めします。

使用しているモジュールについては言及していませんが、それがPEP 249準拠のものであると仮定すると (おそらく cx_Oracle を使用しているでしょう)、名前付きバインド パラメーターを使用して辞書を渡すことができます。典型的なクエリは次のようになります。

query = """select column1 from my_table where id = :my_id"""
bind_vars = {'my_id' : 1}

db_cursor.execute(query, bind_vars)

実際のクエリでは、いくつかの変数 (options.startたとえば) を Python で文字列に変換していますが、SQL ではそれらを引用していません。つまり、暗黙的に数値に変換されています。これはほぼ間違いなく必要ありません。


実際の問題に関連して、2,000 のイベントを完了するのに 1 ~ 2 時間かかるのは、あなたの言う通り、ばかげています。スキーマを投稿していませんが、インデックスが不足していると思います。

イベント番号ごとの平均度数を取得するには、avg()関数を使用する必要があります。これにより、クエリが次のようになります。

select spectraldev.event.eventnumber, avg(degree) as degree
  from spectraldev.degree
  join spectraldev.alignment 
        -- I think this is wrong on your query
    on (degree.version_id = alignment.version_id)
  join spectraldev.event 
    on (alignment.timestamp between event.eventstart and event.eventstop)
  join spectraldev.eventsetup 
    on (spectraldev.event.eventsetup = spectraldev.eventsetup.oid)
 where spectraldev.event.eventnumber >= :start
   and spectraldev.event.eventnumber <= :stop
   and hits >= :minimum_hits
 group by spectraldev.event.eventnumber
 order by spectraldev.event.eventnumber

クエリをフォーマットして、(私の観点から) 少し読みやすくし、インデックスが必要な場所がより明確になるようにしました。

これから判断すると、次のテーブルと列にインデックスが必要です。

  • イベント - eventnumber, eventstart, eventstop,eventsetup
  • 程度 -version_id
  • アライメント - version_idtstamp
  • イベント設定 -oid

そしてどこにいてhitsも。

あなたの問題はインデックスかもしれません。説明計画、スキーマ、または行数を提供していないため、これは推測になります。ただし、テーブル内のかなりの割合の行を選択している場合、CBO使用すべきではないときにインデックスを使用している可能性があります。たとえば、完全なヒントを使用して完全なテーブル スキャンを強制すると、問題が解決する場合があります。/*+ full(event) */

order byが不要な場合は削除すると、クエリが大幅に高速化される場合もあります。

于 2012-10-27T16:33:47.747 に答える