关于Python中执行SQL速度慢的问题,求帮助

ps:刚才的主题没编辑完呢,就发出去了。重发一下。
一条多表联合查询 Sql 语句,在 PL/SQL 里执行需要 100 秒,数据有 8 万条。在 Python 里用 CX_Oracle 里执行这条语句,需要很久。我都没等完过,最长的一次等了半小时。后来用 Pandas 连接数据库查询,速度同样很慢,后来我缩小了选择范围。数据量大概有 3000 条左右,执行时间对比如下:

PL/SQL 15 秒
Python cx_oracle 4 分钟 20 秒
python pandas 5 分钟

所以请教有过此问题经验的大佬给解答一下,是什么造成的差异。我该如何调整呢 感谢!!!



PS:优化 SQL 语句我估计不太可行,语句是需求那边直接给的。如果要优化也是需求那边的问题。我的主要疑问是:
#补充 SQL 语句如下:
select d.cplyno, NVL(SUM(NVL(d.n_sum, 0)), 0)
from (SELECT NVL(N_GET_PRM, 0) n_sum, a.c_ply_no cplyno
FROM T_FIN_PLYEDR_COLDUE@linkzysyscard.regress.rdbms.dev.us.oracle.com A,
[email protected] b
WHERE a.c_cha_cde in (‘55001247’,‘55020299000760’)
and a.c_edr_no is null
and a.c_ply_no = b.c_ply_no
and b.cardno=‘0650mt’
/* and a.c_prod_no like ‘0650mt’|| ‘%’/
and exists
(SELECT C_DPT_CDE
FROM t_department
WHERE c_dpt_cde = a.c_dpt_cde
and c_company_cde in
(SELECT c_company_cde
FROM t_department
WHERE C_DPTACC_CDE = ‘55’))
and b.t_udr_date BETWEEN
to_date(‘2017-11-30 00:00:00’, ‘YYYY-MM-DD HH24:MI:SS’) AND
to_date(‘2017-12-31 23:59:59’, ‘YYYY-MM-DD HH24:MI:SS’)
and b.c_b2b_udr_mrk <> ‘X’
and N_GOT_PRM = 0
and T_CHARGE_TM is null
union all
SELECT NVL(N_GET_PRM, 0) n_sum, a.c_edr_no cplyno
FROM T_FIN_PLYEDR_COLDUE@linkzysyscard.regress.rdbms.dev.us.oracle.com A,
[email protected] b,
[email protected] c
WHERE a.c_cha_cde in (‘55001247’,‘55020299000760’)
and a.c_edr_no is not null
and a.c_edr_no = b.c_edr_no
and b.c_ply_no=c.c_ply_no
/
and a.c_prod_no like ‘0650mt’ || ‘%’*/
and exists
(SELECT C_DPT_CDE
FROM t_department
WHERE c_dpt_cde = a.c_dpt_cde
and c_company_cde in
(SELECT c_company_cde
FROM t_department
WHERE C_DPTACC_CDE = ‘55’))
and b.t_udr_date BETWEEN
to_date(‘2017-11-30 00:00:00’, ‘YYYY-MM-DD HH24:MI:SS’) AND
to_date(‘2017-12-31 23:59:59’, ‘YYYY-MM-DD HH24:MI:SS’)
and b.c_b2b_udr_mrk <> ‘X’
and N_GOT_PRM = 0
and c.cardno=‘0650mt’
and T_CHARGE_TM is null) d

group by d.cplyno
order by d.cplyno;
关于Python中执行SQL速度慢的问题,求帮助


21 回复

问题所在,多半是是一次性把数据载入内存的开销。


我无法理解你的问题

查询数据的游标 cursor 不要执行 cursor.fetchall()一次性取出数据,试试 for data in cursor 逐条去取数据,因为 cursor 是一个迭代器

在 python 里 我测试: 只执行 sql 语句 curs.execute(sql) ,而不获取查询结果 速度同样很慢。请问下,只执行语句,不 fetchall,会占用很多内存吗?

嗯,是的。我并没有 fetchall。只是 curs.execute(sql)。时间差异依然是那么大~

优化 sql 或者 strace -p 看卡在哪

有完整的 python 代码么?

就是很简单的连数据库流程,
conn = cx_Oracle.connect(‘xxxxx/[email protected]:xx/xxx’)
curs = conn.cursor()
query_sql ="sql 语句"
curs.execute(query_sql)
#query_data = curs.fetchll()
#print(query_data)
curs.close()
conn.close()

就是 fetchall 卡住了。

不能在程序里面,多表联合查询用一个 sql 语句,能出来就奇怪了,要建立数据模型
和 pl/sql 比较速度没有意义
你用哪种语言都是这样结局,除非 foxpro 或者 powerbuilder 这样本身就是数据库为核心的开发系统
可以什么都不管塞进去 sql

您看下我补发的图片,从反映上看时间 应该还是浪费在了 execute 的执行上

ok。那就不清楚了。

不能用一个 sql 语句。是不能执行还是速度慢啊!我从测试上来看,数据量少的话,还是能获取执行结果的。再请问 如果不写在一个 sql 里的话。除了拆分 SQL 语句 还有什么好的方案可以实现吗?

看了这么长的 sql 语句,表示我不想说任何话

抓个包用 wireshark 看看吧,应该可以解析这个协议

  1. python connector 的问题

    2. 游标(参考二楼)

    使用
    for row in cur:
    替代
    cur.fetchall()


    参考: https://stackoverflow.com/questions/26783735/python-5x-slower-than-perl-mysql-query

和第二条应该没关系,我测试过第二种方案,效果一样。可能是 connector 的原因。但是我用 pandas 直接连接数据库执行语句,效果和用 cx_oracle 一样慢 。所以现在我也不是很清楚瓶颈卡在哪里了。您有什么好的提议吗?

感谢您的回复~刚才已经找到问题所在啦,原因是我错误的打乱了 sql 语句的格式造成的问题。他们给我 sql 语句之后,我用 双引号 “sql 语句” 存放,然后对缩进格式更改过。最后我直接使用 三引号代码块 “”“sql 语句”"" 放 原格式语句 就好啦、

原因已经找到:我错误的打乱了 sql 语句的格式造成的问题。他们给我 sql 语句之后,我用 双引号 “sql 语句” 存放,然后对缩进格式更改过。最后我直接使用 三引号代码块 “”“sql 语句”"" 放 原格式语句。可能是某些空格
或者缩进单位影响了 sql 的执行效率。
经验 :大段 SQL 语句要小心更改。最好直接使用三引号代码块

结贴追加补图!

如果是 buffer cursor 的话,那么 execute 阶段就已经完成数据加载到内存解析完成了吧
而且事实上 cx_oracle 是用 c 写的啊,和 python 语言性能并未有直接关系
试过 pymysql 纯 python 写的从 mysql 取出百万条数据也不是很慢的吧

改 sql 要小心,确实。

回到顶部