【问题标题】:Load/use SQL function on Python (avoid round trip)在 Python 上加载/使用 SQL 函数(避免往返)
【发布时间】:2015-11-11 23:35:59
【问题描述】:

我正在编写的 Python 代码与 PostgreSQL 数据库建立了psycopg2 连接。我需要从这个数据库中的数据构建一些报告,所以我有几个 Python procs 定期运行并从一些表和漂亮的查询中创建一个 csv 文件。

我在这里面临的问题是我需要在我的 csv 报告中包含一个列,该列是存储在 PostgreSQL 数据库中的函数的结果。该数据库由另一组人管理,因此我无法写入。我可以很容易地看到该函数的内容并模拟 Python 上的行为并获得我需要计算的列值,但在这种情况下,该函数会定期更改,并且不断更新 Python 函数是没有意义的。

所以我的问题是,每次我的代码连接到数据库时,是否有可能以某种方式将数据库函数加载到 Python 代码中。我可以在数据库本身上实际使用该函数,但想象一下从 Python 代码对数据库函数进行 90 万次调用以计算值,根本无法扩展。

编辑:添加sql函数

CREATE OR REPLACE FUNCTION public.p_start(integer, integer)
 RETURNS numeric
 LANGUAGE sql
 IMMUTABLE
AS $function$
SELECT CASE WHEN $1 = 0 AND $2 = 0 THEN 0.2760
            WHEN $1 = 0 AND $2 = 1 THEN 0.0684
            WHEN $1 = 0 AND $2 = 2 THEN 0.0277
            WHEN $1 = 0 AND $2 = 3 THEN 0.0189
            WHEN $1 = 0 AND $2 = 4 THEN 0.0038
            WHEN $1 = 0 AND $2 = 5 THEN 0.0098
            WHEN $1 = 1 AND $2 = 1 THEN 0.5501
            WHEN $1 = 1 AND $2 = 2 THEN 0.2264
            WHEN $1 = 1 AND $2 = 3 THEN 0.1203
            WHEN $1 = 1 AND $2 = 4 THEN 0.0804
            WHEN $1 = 1 AND $2 = 5 THEN 0.0839
            ELSE 0.1 END;
$function$

谢谢

【问题讨论】:

  • 那么您想将查询转换为 Python 函数吗?还是您想从 Python 执行查询?
  • @zom-pro 只要我避免往返数据库并获得可以直接在 Python 上使用并写入 csv 的结果,其中任何一个都是有效的。
  • 查询有多大?我问是因为如果翻译成 Python,你会失去 SQL 优化。这可能是使用数据库最有力的理由,除非查询很小,在这种情况下它无关紧要。
  • 数据库函数是用PL/PgSQL写的吗? PL/Python?其他?它自己做数据库访问吗?

标签: python database postgresql psycopg2


【解决方案1】:

这是一个简单的 sql 语言函数。

除非你可以依靠它的结构保持足够稳定,你可以为函数体编写一个简单的解析器,从pg_procprosrc 列中获取它的源代码,我认为你不走运。我不想这样做,因为它非常脆弱。

您应该要求数据库团队将此映射存储在一个小表中而不是一个函数中,然后您可以只查询表内容并缓存它们。他们仍然可以拥有一个从表中返回选择结果的函数,并且在大多数情况下它会被有效地内联,并且不会影响与使用该函数的现有应用程序的兼容性。例如。如果信息在表格probabilities 中,则函数为:

CREATE OR REPLACE FUNCTION public.p_start(integer, integer)
 RETURNS numeric
 LANGUAGE sql
 IMMUTABLE
AS $function$
SELECT coalesce(
  SELECT probability FROM probabilities WHERE a = $1 and b = $2
0.1)
$function$

如果事先知道可能输入值的范围,您可以生成完整功能域的映射并将其缓存在您的应用中,例如:

test=> SELECT startval, endval, p 
       FROM generate_series(0,1) startval 
       cross join generate_series(0,5) endval 
       cross join p_start(startval, endval) p;

 startval | endval |   p    
----------+--------+--------
        0 |      0 | 0.2760
        1 |      0 |    0.1
        0 |      1 | 0.0684
        1 |      1 | 0.5501
        0 |      2 | 0.0277
        1 |      2 | 0.2264
        0 |      3 | 0.0189
        1 |      3 | 0.1203
        0 |      4 | 0.0038
        1 |      4 | 0.0804
        0 |      5 | 0.0098
        1 |      5 | 0.0839
(12 rows)

这很容易变成 Python 字典以进行本地查找。

这仅在函数的域是有限且已知的情况下才有效。


顺便说一句,将其定义为IMMUTABLE 然后重新定义它是错误的,除非他们DROP 和重新CREATE 它以确保不依赖旧定义。它应该被声明为STABLE。以可以产生不同值的方式重新定义 IMMUTABLE 函数如果在任何表达式索引中使用该函数,则会导致不正确的查询结果。

【讨论】:

    猜你喜欢
    • 2010-10-22
    • 2016-03-24
    • 2012-07-20
    • 2013-08-07
    • 2018-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多