2017-09-15 53 views
1

这是一个由两部分组成的问题。如果你正在检查这个,谢谢你的时间!我的Postgres查询如何执行得更快?我可以使用Python来提供更快的迭代吗?

  1. 有没有办法让我的查询速度更快?

    我以前问过一个问题here,并最终能够自己解决问题。

    但是,当我针对包含40,000多条记录的数据库运行时,我设计的查询结果非常慢(25分钟以上)。

    该查询服务于其目的,但我希望你们中的一位聪明人能够指出我如何使查询以更优选的速度执行。

    我的查询:

    with dupe as (
        select 
         json_document->'Firstname'->0->'Content' as first_name, 
         json_document->'Lastname'->0->'Content' as last_name, 
         identifiers->'RecordID' as record_id 
        from (
         select *, 
           jsonb_array_elements(json_document->'Identifiers') as identifiers 
         from staging 
        ) sub 
        group by record_id, json_document 
        order by last_name 
    ) 
    
    select * from dupe da where (
        select count(*) from dupe db 
        where db.record_id = da.record_id 
    ) > 1; 
    

    此外,一些示例数据:

    行1:

    { 
         "Firstname": "Bobb", 
         "Lastname": "Smith", 
         "Identifiers": [ 
          { 
           "Content": "123", 
           "RecordID": "123", 
           "SystemID": "Test", 
           "LastUpdated": "2017-09-12T02:23:30.817Z" 
          }, 
          { 
           "Content": "abc", 
           "RecordID": "abc", 
           "SystemID": "Test", 
           "LastUpdated": "2017-09-13T10:10:21.598Z" 
          }, 
          { 
           "Content": "def", 
           "RecordID": "def", 
           "SystemID": "Test", 
           "LastUpdated": "2017-09-13T10:10:21.598Z" 
          } 
         ] 
    } 
    

    行2:

    { 
         "Firstname": "Bob", 
         "Lastname": "Smith", 
         "Identifiers": [ 
          { 
           "Content": "abc", 
           "RecordID": "abc", 
           "SystemID": "Test", 
           "LastUpdated": "2017-09-13T10:10:26.020Z" 
          } 
         ] 
    } 
    
  2. 如果我把在我的查询结果中,或一部分结果放入可以使用Pandas进行操作的Python环境中,我如何迭代我的查询(或子查询)的结果以达到与原始查询相同的最终结果?

    是否有一种更简单的方法,使用Python,以与Postgres相同的方式遍历未嵌套的json数组?

    例如,在执行此查询后:

    select 
        json_document->'Firstname'->0->'Content' as first_name, 
        json_document->'Lastname'->0->'Content' as last_name, 
        identifiers->'RecordID' as record_id 
    from (
         select *, 
           jsonb_array_elements(json_document->'Identifiers') as identifiers 
         from staging 
        ) sub 
    order by last_name; 
    

    如何,使用Python /熊猫,我可以采取查询的结果,并执行类似:

    da = datasets[query_results] # to equal my dupe da query 
    db = datasets[query_results] # to equal my dupe db query 
    

    然后执行

    相当于
    select * from dupe da where (
        select count(*) from dupe db 
        where db.record_id = da.record_id 
    ) > 1; 
    

    in Python?

如果我在这里没有提供足够的信息,我很抱歉。我是一名Python新手。任何和所有的帮助,非常感谢!谢谢!!

+1

首先从使用CTE('WITH'查询)转换为使用子查询在FROM表单。见https://blog.2ndquadrant.com/postgresql-ctes-are-optimization-fences/ –

+0

感谢克雷格!我现在正在阅读这篇文章,看起来这可能会有所帮助。 +1 – jmoneygram

+2

一旦你弄清楚了方法,它在SQL中执行的事情几乎总是比客户端迭代更快。有时需要一些额外的思考。在编辑中,请为您的查询显示“EXPLAIN ANALYZE”输出。 –

回答

1

尝试以下,免去了您COUNT(*),而是使用存在。

with dupe as ( 
    select id, 
    json_document->'Firstname'->0->'Content' as first_name, 
    json_document->'Lastname'->0->'Content' as last_name, 
    identifiers->'RecordID' as record_id 
    from 
    (select 
     *, 
     jsonb_array_elements(json_document->'Identifiers') as identifiers 
     from staging) sub 
     group by 
     id, 
     record_id, 
     json_document 
     order by last_name) 
select * from dupe da 
    where exists 
    (select * 
     from dupe db 
     where 
     db.record_id = da.record_id 
     and db.id != da.id 
    ) 
+0

谢谢!事实上,这确实极大地加快了我的查询速度。我对你上面发布的查询做了一个小小的修改,但总的想法很明显。再次感谢! – jmoneygram

+0

我有打字错误吗?让我知道你改变了什么,我会更新后代的答案。 –

+0

如上所述,'dupe da'不包含主键'id'。我只需要将'id'添加到我的'WITH dupe AS'查询中的SELECT语句中的项目列表中,以便可以通过我的最终SELECT *访问它。 ;) 嵌套的子查询已经执行SELECT *,所以'id'不需要包含在那里的SELECT语句中。刚添加到GROUP BY列表中。 – jmoneygram

1

考虑读取Postgres json列类型的原始未找到的值,并使用pandas json_normalize()将其绑定到一个平坦的数据框中。从那里使用熊猫drop_duplicates

为了演示,下面解析您的一个JSON数据转换成三排数据帧对应于每个标识符记录:

import json 
import pandas as pd 

json_str = ''' 
{ 
     "Firstname": "Bobb", 
     "Lastname": "Smith", 
     "Identifiers": [ 
      { 
       "Content": "123", 
       "RecordID": "123", 
       "SystemID": "Test", 
       "LastUpdated": "2017-09-12T02:23:30.817Z" 
      }, 
      { 
       "Content": "abc", 
       "RecordID": "abc", 
       "SystemID": "Test", 
       "LastUpdated": "2017-09-13T10:10:21.598Z" 
      }, 
      { 
       "Content": "def", 
       "RecordID": "def", 
       "SystemID": "Test", 
       "LastUpdated": "2017-09-13T10:10:21.598Z" 
      } 
     ] 
} 
''' 

data = json.loads(json_str)  
df = pd.io.json.json_normalize(data, 'Identifiers', ['Firstname','Lastname']) 

print(df)  
# Content    LastUpdated RecordID SystemID Lastname Firstname 
# 0  123 2017-09-12T02:23:30.817Z  123  Test Smith  Bobb 
# 1  abc 2017-09-13T10:10:21.598Z  abc  Test Smith  Bobb 
# 2  def 2017-09-13T10:10:21.598Z  def  Test Smith  Bobb 

为你的数据库,考虑你的DB-API连接如psycopg2sqlAlchemy并相应地将每个json解析为一个字符串。诚然,有可能是其他方式如psycopg2 docs看到,但低于接收数据,文字和分析的Python端处理JSON:

import psycopg2 
conn = psycopg2.connect("dbname=test user=postgres") 

cur = conn.cursor()  
cur.execute("SELECT json_document::text FROM staging;") 

df = pd.io.json.json_normalize([json.loads(row[0]) for row in cur.fetchall()], 
           'Identifiers', ['Firstname','Lastname']) 

df = df.drop_duplicates(['RecordID']) 

cur.close() 
conn.close() 
+0

感谢您的帮助!非常酷的建议。 – jmoneygram

+0

太棒了!乐意效劳。 – Parfait

相关问题