【问题标题】:DatabaseError: ORA-01555: snapshot too oldDatabaseError: ORA-01555: 快照太旧
【发布时间】:2020-07-05 21:09:08
【问题描述】:

我要下载的数据大约是 Oracle 11g 数据库中的 45,000,000 行和 38 列。

当我尝试在 python 中下载 chunksize=50000 的数据时,

DatabaseError: ORA-01555: 快照太旧

此错误总是发生在块的同一点(code(1)_at 9th session)。

但是,当我按日期分别下载相同的数据时,下载的数据没有任何错误。(代码(2))

第一次,我猜“DatabaseError: ORA-01555”这个错误是因为按chunksize 50000下载可能需要太长时间。但是一天的数据大约有 300,000 行,大于 50000 块大小。谁能告诉我你的意见?

以下是我的代码。

(1) 按块大小下载

# SQL Query
tmp = pd.read_sql_query("SELECT * FROM Database WHERE TIME_STAMP BETWEEN TO_TIMESTAMP('2019-12-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') AND TO_TIMESTAMP('2019-12-31 23:59:59', 'YYYY-MM-DD HH24:MI:SS')", con = con, chunksize = 50000)
gen = map(pd.DataFrame, tmp)

# Download by chunk
cnt = 0
flag = 0
for index, data in enumerate(gen):
    if flag == 0 or index == 0:
        df = pd.DataFrame(data)
        flag = 1
    elif index % 100 != 0:
        df = pd.concat([df,pd.DataFrame(data)], axis = 0)        
    elif index % 100 == 0:
        df = pd.concat([df,pd.DataFrame(data)], axis = 0)   
        cnt = cnt+1

        # Save as CSV file
        df.to_csv("{0}{1}{2}".format("D:\\Data",cnt,".csv"), header=True, index=False)
        print("Index: ", index)
        print("Shape: ", df.shape)
        print("==========={}th Session Ended==============".format(cnt))

        # Flush out Memory
        del df
        gc.collect()
        flag = 0

(总是在第 9 届会议,错误出来)

(2) 按日期下载

for i in range(1,32):
    print("============ 2019-12-",i," ============")
    date = "2019-12-{}".format(i)

    # SQL Query
    tmp = pd.read_sql_query("SELECT * FROM Database WHERE TIME_STAMP BETWEEN TO_TIMESTAMP('2019-12-{} 00:00:00', 'YYYY-MM-DD HH24:MI:SS') AND TO_TIMESTAMP('2019-12-{} 23:59:59', 'YYYY-MM-DD HH24:MI:SS')".format(i,i), con = con)

    # Save as CSV file
    tmp.to_csv("{0}{1}{2}{3}".format("D:\\","ByDate\\",date,".csv"), header=True, index=False)

    # Flush out Memory
    del tmp
    gc.collect()

【问题讨论】:

    标签: python sql oracle


    【解决方案1】:

    当您启动查询时,Oracle 必须从那一刻起保持逻辑一致的视图,直到它完成响应。由于底层数据通过用户事务发生变化,Oracle 将增量映射到回滚段和撤消空间。如果太多数据更改并且撤消空间用尽,Oracle 将无法再维护您所请求数据的一致视图,并且必须放弃查询 - 因此您看到的错误。见这里:http://www.dba-oracle.com/t_ora_01555_snapshot_old.htm

    除非您可以修改数据库以便为事务提供更多撤消空间,否则您可能不得不在数据库空闲时等待运行查询或将数据分成更小的块。

    【讨论】:

    • 哦,我以为我误解了 pd.read_sql_query 部分。在我阅读您的解释之前,在代码(1)中,我认为如果我设置了 chunksize 选项,pd.read_sql_query 只是将查询保存在迭代器中,而不是当时实际发送它们。所以,我想,当我迭代包含查询的迭代器时,实际的查询(按块选择 *)实际上是发送到 Oracle 的。(在 for 循环内)但是,根据您的解释,所有查询都是一次发送的,在 for 循环之外。
    • 那么我的理解正确吗? >code (1): 快照是在这个时候拍摄的。 tmp = pd.read_sql_query("SELECT * FROM Database ~~", con = con, chunksize = 50000)(SQL 查询是在 for 循环之外发送的。) >code (2):此时拍摄了快照。 tmp = pd.read_sql_query("SELECT * FROM Database ~~".format(i,i), con = con)(每次都在for循环内发送SQL查询)谢谢您的回复:)
    • 是的,看起来是正确的。 code(1) 有一个更大的结果集,由于其他用户活动/事务进行更改,数据库返回所需的时间太长。 code(2) 成功是因为它一次要求的结果集要小得多。您可以通过返回更大集合中的行(一次远大于 50,000 行)来使 code(1) 工作。
    猜你喜欢
    • 1970-01-01
    • 2016-02-13
    • 2015-06-17
    • 2010-12-13
    • 2012-08-11
    • 2015-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多