我的Python脚本当前遇到问题,当我从cursor.execute()为特定函数执行SQL函数时,它运行函数,函数完成,然后脚本挂起大约五个小时之前的某个地方恢复该计划的其余部分。
我在pgAdminIII中观察我的函数的服务器状态,因为它是从Python调用的,当函数完成时,服务器只显示与我的python-user的打开连接。在事务中空闲之前,但在添加conn.set_isolation_level(0)之后,它只显示打开的连接。
我还在cursor.execute()周围放置了打印件,但是需要五个小时才能继续执行以下print语句。我试过杀死连接并重新启动它无济于事。我完全从我的脚本中删除了函数调用,因此它是我的脚本处理的唯一过程。没有任何效果。
困难在于双方都指向对方作为问题的根源。我假设它是这种特定功能的某种交互作用。在运行特定函数后,也许没有信号从postgres发送回python?其他任何函数都没有相同的执行方法的问题。
想法?解决方案? - 我正在考虑超时,但运行时间可能在20分钟到2小时之间变化。 - 它运行的函数创建一个表并只返回一个表示“完成”的字符串,所有操作在服务器状态中作为活动函数消失后在数据库中计算。
以下是我用于复制问题的代码,与我的主脚本隔离:
#!/usr/bin/env python
import sys
import os
import smtplib
import ftplib
import gzip
import logging
import shutil
import argparse
import traceback
import subprocess
from email.mime.text import MIMEText
import psycopg2
import psycopg2.extras
import psycopg2.extensions
from psycopg2 import OperationalError
pg_db = "ppl"
pg_port = "5432"
pg_user = "<user>"
pg_pass = "<pass>"
pg_host = "<host>"
# connect to database
try:
conn = psycopg2.connect(database=pg_db,
port=pg_port,
user=pg_user,
password=pg_pass,
host=pg_host)
conn.set_isolation_level(0)
except:
print "Unable to connect to the database."
cur = conn.cursor()
print 'Starting select <function1>'
cur.execute("select <function1>(999999, null );")
print 'Assign variable...'
a = cur.fetchall()
print 'Done'
print 'Starting select <function2>'
cur.execute("select <function2>(999999, null );")
print 'Assign variable...'
b = cur.fetchall()
print 'Done'
print a
print b
conn.close()
sys.exit()
然后我根据这些结果提出了一个strace:
<previous function statements for about 4k lines>
write(1, "Starting select <function>"..., 45) = 45
sendto(3, "Q\0\0\0009select <function>"..., 58, MSG_NOSIGNAL, NULL, 0) = 58
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "T\0\0\0001\0\1<function_name>\0"..., 16384, 0, NULL, NULL) = 500
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "N\0\0\0mSINFO\0C00000\0Mv_eval_table "..., 16384, 0, NULL, NULL) = 110
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "N\0\0\4\247SINFO\0C00000\0Mcmd := CREATE"..., 16384, 0, NULL, NULL) = 1192
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "N\0\0\23hSINFO\0C00000\0Mcmd := \t--For"..., 16384, 0, NULL, NULL) = 4969
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 84
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 672
...
brk(0xbe9000) = 0xbe9000
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 84
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 168
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 1008
...
<does this for about 600k more lines before executing the rest of the script, I am assuming it is indefinitely looping until a timeout>
接下来,我为一个函数运行了一个cProfile,该函数包含了第二个调用第二个函数的代码块:
Tue Jan 15 16:04:50 2013 function2_prof
7 function calls in 15755.988 CPU seconds
Random listing order was used
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 {method 'cursor' of 'psycopg2._psycopg.connection' objects}
1 0.000 0.000 15755.988 15755.988 test_sql_sub2.py:48(LR2)
1 15755.988 15755.988 15755.988 15755.988 {method 'execute' of 'psycopg2._psycopg.cursor' objects}
1 0.000 0.000 15755.988 15755.988 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.000 0.000 0.000 0.000 {method 'close' of 'psycopg2._psycopg.cursor' objects}
1 0.000 0.000 0.000 0.000 {method 'fetchall' of 'psycopg2._psycopg.cursor' objects}
答案 0 :(得分:1)
我认为你的功能比你意识到的更多。看看你的strace:
brk(0xbe9000) = 0xbe9000
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 84
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 168
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 1008
brk
意味着“给我更多的记忆”,所以很明显Python正在积累数据。 poll
检查是否有任何数据等待;正回报值(此处为1
)表示存在。 recvfrom
读取该数据并返回读取的字节数。
所以看起来Postgres正在向你发送很多的数据,以至于它需要花费大量的时间才能收到。我对Postgres的有线格式了解不多,但是每次民意调查中的license_row_i...
听起来肯定会让你收到大量的行数。该函数不再显示为执行,因为它不是;工作已经完成,Postgres现在只是将结果发回。
难怪双方都在责备对方;问题出在中间。 :)
编辑:啊哈,更多信息涉及RAISE INFO
。 Psycopg2确实存储了所有这些通知,on the connection object。
它只保留最后五十,但如果您向客户发送超过五十万通知,则需要一段时间才能将其转换为Python字符串,丢掉最旧的如果命令行客户端完全忽略它们(或者甚至只是在C中执行此操作),它自然要快得多。
所以简单的解决方案是“不要那样做”。 :)你也可以configure Postgres not to send these to the client,但当然他们最终无法进行调试。我可以看到,没有办法让psycopg2不收集发送给客户的通知。
答案 1 :(得分:0)
问题是由于SQL函数中的多个for循环中有一行:
raise info 'license_row_id := %', rec.license_row_id;
这些引发信息消息在某种程度上不是由python处理的,因为它们是bash和pgAdmin。我的猜测是因为它们未处理,它们保持循环和处理并要求更多内存,直到它无法处理,最后在没有警告或错误的情况下放弃加注信息并恢复程序。
我注释掉了这个不必要的提升信息行,整个脚本在20分钟内运行,这是程序的正常运行时间。如果有人知道如何使python句柄从postgresql提出信息消息,甚至可能进一步回答这个问题。