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)

它为许多事件返回一堆degrees (12.34 等),这些事件由唯一编号(eventnumber如 346554)标识。

所以我得到一个这样的表:

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 来执行此操作,但是 fetch 命令需要 1-2 小时才能完成大约 2000 个事件,这太慢了,因为我需要处理大约 1000000 个事件。

这是我的获取部分,需要很长时间:

_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_id,tstamp
  • 活动设置 -oid

hits以及可能在哪里。

说了这么多,你的问题可能索引。你没有提供你的解释计划或模式,或者行数,所以这将是一个猜测。但是,如果您在表中选择很大比例的行,CBO可能会在不应该使用索引时使用索引。例如,使用完整提示强制进行全表扫描可能会解决您的问题/*+ full(event) */

order by如果不需要,删除, 也可能会显着加快您的查询速度。

于 2012-10-27T16:33:47.747 回答