用Python实现PostgreSQL数据库的快速复杂SQL查询

用Python实现PostgreSQL数据库的快速复杂SQL查询,python,database,postgresql,performance,pandas,Python,Database,Postgresql,Performance,Pandas,我有一个庞大的数据集,在PostgreSQL数据库中有+50万条记录,需要大量的计算和内部连接 Python是Psycopg2的首选工具 使用20000条记录的fetchmany运行进程需要几个小时才能完成 执行需要按顺序进行,因为需要分别获取50M的每个记录,然后需要运行另一个查询(在下面的示例中),然后返回结果并将其保存在单独的表中 在每个表上正确配置索引(总共5个表),复杂查询(返回计算值-下面的示例)大约需要240MS才能返回结果(当数据库未加载时) 芹菜用于在单独的表中插入计算值的数据

我有一个庞大的数据集,在PostgreSQL数据库中有+50万条记录,需要大量的计算和内部连接

PythonPsycopg2的首选工具

使用20000条记录的fetchmany运行进程需要几个小时才能完成

执行需要按顺序进行,因为需要分别获取50M的每个记录,然后需要运行另一个查询(在下面的示例中),然后返回结果并将其保存在单独的表中

在每个表上正确配置索引(总共5个表),复杂查询(返回计算值-下面的示例)大约需要240MS才能返回结果(当数据库未加载时)

芹菜用于在单独的表中插入计算值的数据库

我的问题是关于减少总体运行时间和更快生成结果/计算的常见策略。 换句话说,一个接一个地检查所有记录,通过第二次查询计算字段值,然后保存结果的有效方法是什么

更新:

在试图混淆敏感细节时,我无意中漏掉了一条重要信息。对不起

原始的
SELECT
查询计算从不同表聚合的值,如下所示:

SELECT CR.gg, (AX.b + BF.f)/CR.d AS calculated_field
FROM table_one CR
  LEFT JOIN table_two AX ON EX.x = CR.x
  LEFT JOIN table_three BF ON BF.x = CR.x
WHERE CR.gg = '123'
GROUP BY CR.gg;

PS:SQL查询是由我们经验丰富的DBA编写的,因此我相信它已得到优化。

因为您正在查询中执行联接,所以逻辑上要做的是解决它,这意味着创建一个汇总表,这个汇总表(位于数据库中)将保存最终联接的数据集,因此,在python代码中,您只需从中获取/选择数据


另一种方法是使用物化视图

因为您在查询中进行连接,所以逻辑上要做的事情是绕过它,这意味着创建一个汇总表,这个汇总表(位于数据库中)将保存最终的连接数据集,因此在python代码中,您只需从中获取/选择数据

另一种方法是使用物化视图
  • 不要循环记录,并为每个记录重复调用DBMS
  • 相反,让DBMS处理大块(最好是全部)数据
  • 然后,让它说出所有的结果
  • 下面是我的推特吸盘的一个片段(带有一个相当复杂难看的查询)


    • 不要循环记录,并为每个记录重复调用DBMS
    • 相反,让DBMS处理大块(最好是全部)数据
    • 然后,让它说出所有的结果
    下面是我的推特吸盘的一个片段(带有一个相当复杂难看的查询)



    我接受了@wildplasser的建议,将计算操作作为一个函数移动到数据库中。 结果非常有效,至少可以说总运行时间降到了分钟/小时

    重述:

    • 不再按顺序提取数据库记录 前面提到的
    • 计算通过函数在数据库内部进行

    我接受了@wildplasser的建议,将计算操作作为一个函数移动到数据库中。 结果非常有效,至少可以说总运行时间降到了分钟/小时

    重述:

    • 不再按顺序提取数据库记录 前面提到的
    • 计算通过函数在数据库内部进行

    在psql中运行相同的裸查询,以获得向pyhon前端传输/从pyhon前端传输数据所需的估计时间,以及向python结构转换/从python结构转换数据所需的时间。
    。。。单个查询大约需要…
    什么是单个查询???@wildplasser每次查询数据集时的单个查询(包括连接命令),即:
    select*from_one er left join table_two ex ON ex.x=er.y left join table_three ef ON ef.x=er.z其中er.gg='123'group by er.gg和:什么是非单一查询???注意:er.gg的
    分组是没有用的,因为只有一个组(没有聚合):不要这样做!(每项需要两次往返数据库+解析+执行)相反,让数据库计算您需要的所有记录的所有值,并在一次扫描中获取所有结果。在psql中运行相同的查询,以获得与pyhon前端之间传输所需的估计时间,以及在python结构中转换数据的时间。
    。。。单个查询大约需要…
    什么是单个查询???@wildplasser每次查询数据集时的单个查询(包括连接命令),即:
    select*from_one er left join table_two ex ON ex.x=er.y left join table_three ef ON ef.x=er.z其中er.gg='123'group by er.gg和:什么是非单一查询???注意:er.gg的
    分组是没有用的,因为只有一个组(没有聚合):不要这样做!(每个项目需要两次往返数据库+解析+执行)相反,让数据库计算您需要的所有记录的所有值,并在一次扫描中获取所有结果。感谢您详细的回答。你的观点完全有道理,而不是关于查询的观点,因为我犯了一个错误,并添加了一个更新来澄清问题。另外,感谢您的代码片段。注意:范围中没有
    ez.
    别名。请发布真正的查询(加上表定义,等等,plonk?)谢谢你详细的回答。你的观点完全有道理,而不是关于查询的观点,因为我犯了一个错误,并添加了一个更新来澄清问题。另外,感谢您的代码片段。注意:范围中没有
    ez.
    别名。请发布真实的查询(加上表格)
    def fetch_referred_tweets(self):
        self.curs = self.conn.cursor()
        tups = ()
        selrefd = """SELECT twx.id, twx.in_reply_to_id, twx.seq, twx.created_at
        FROM(
         SELECT tw1.id, tw1.in_reply_to_id, tw1.seq, tw1.created_at
         FROM tt_tweets tw1
         WHERE 1=1
          AND tw1.in_reply_to_id > 0
          AND tw1.is_retweet = False
          AND tw1.did_resolve = False
          AND NOT EXISTS ( SELECT * FROM tweets nx
                           WHERE nx.id = tw1.in_reply_to_id)
          AND NOT EXISTS ( SELECT * FROM tt_tweets nx
                           WHERE nx.id = tw1.in_reply_to_id)
         UNION ALL
        SELECT tw2.id, tw2.in_reply_to_id, tw2.seq, tw2.created_at
         FROM tweets tw2
         WHERE 1=1
          AND tw2.in_reply_to_id > 0
          AND tw2.is_retweet = False
          AND tw2.did_resolve = False
          AND NOT EXISTS ( SELECT * FROM tweets nx
                           WHERE nx.id = tw2.in_reply_to_id)
          AND NOT EXISTS ( SELECT * FROM tt_tweets nx
                           WHERE nx.id = tw2.in_reply_to_id)
         -- ORDER BY tw2.created_at DESC
        )twx
         LIMIT %s;"""
          # -- AND tw.created_at < now() - '15 min':: interval
          # -- AND tw.created_at >= now() - '72 hour':: interval
    
        count = 0
        uniqs = 0
        self.curs.execute(selrefd, (quotum_referred_tweets, ) )
        tups = self.curs.fetchmany(quotum_referred_tweets)
        for tup in tups:
          if tup == None: break
          print ('%d -->> %d [seq=%d] datum=%s' % tup)
          self.resolve_list.append(tup[0] ) # this tweet
          if tup[1] not in self.refetch_tweets:
              self.refetch_tweets[ tup[1] ] = [ tup[0]] # referred tweet
              uniqs += 1
    
          count += 1
    
        self.curs.close()
    
    select er.gg, er.z, er.y
    from table_one er
    where er.gg = '123'
    -- or:
    where er.gg >= '123'
      and er.gg <= '456'
    ORDER BY er.gg, er.z, er.y -- Or: some other ordering
        ;