2017-09-15 61 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

相關問題