优化 Oracle 数据库查询/fetchall
Posted
技术标签:
【中文标题】优化 Oracle 数据库查询/fetchall【英文标题】:Optimizing Oracle database query/fetchall 【发布时间】:2012-10-27 14:20:05 【问题描述】:数据库设计远非最佳,但我必须处理它,现在我真的陷入困境。
编辑:我正在使用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)
它会为许多事件返回一堆 degree
s(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
等等……
现在我需要为每个事件创建一个具有平均度数的字典(将所有相应的浮点数相加并除以它们的数量)。
我认为这可以在 SQL 中完成,但我无法让它工作。目前我正在使用 python 来执行此操作,但是 fetch 命令需要 1-2 小时才能完成大约 2000 个事件,这太慢了,因为我需要处理大约 1000000 个事件。
这是我的抓取部分,需要很长时间:
_degrees = []
for degree, eventNumber in cursor.fetchall():
_degrees.append([eventNumber, degree])
然后排序(非常快,
_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 部分?
【问题讨论】:
【参考方案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 中引用它们,这意味着它们被隐式转换回数字。这几乎绝对不需要。
相对于您的实际问题,1-2 小时完成 2,000 个事件是正确的,荒谬的。您尚未发布架构,但我猜您缺少任何 indexes。
要获得每个事件编号的平均度数,您应该使用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 hint、/*+ full(event) */
强制进行全表扫描可能会解决您的问题。
删除order by
(如果不需要)也可能会显着加快您的查询速度。
【讨论】:
非常感谢您的回答,我还在努力完全理解它; ) 我还不知道绑定参数,需要检查它们!是否有一本“标准”书或某本书可以推荐用于掌握 SQL?我只使用文档,但对于 Oracle “菜鸟”来说它是非常核心的(我什至不知道索引是什么,如果我读过一本关于 Oracle 的书,我相信我会;) 最好的事情是有人向您展示!我从来没有从一本书中学到过,但Tech on the Net 是一个非常好的语法资源。你问的是基本的数据库概念......我不知道从哪里开始建议你。仅仅搜索基本的 SQL 就能让你到达某个地方,但忽略 w3 学校,因为它已广受质疑。在我看来,没有什么比练习更好的了。以上是关于优化 Oracle 数据库查询/fetchall的主要内容,如果未能解决你的问题,请参考以下文章