如何遍历具有大量记录的数据库表

时间:2019-01-05 11:45:43

标签: python postgresql ibm-cloud-functions

我正在使用Scrapy库抓取一个销售汽车的网站。

我正在使用Python和IBM Cloud函数以及Scrapy来实现这一目标。这个想法是每天通过IBM Cloud操作刮取该站点,并将每辆车都添加到Postgres数据库的vehicles表中。那部分工作正常。

vehicles表的结构如下:

enter image description here

第一步是将数据列以外的所有内容(这是汽车的详细信息,第二步需要添加这些内容)添加到vehicles表中。很好。

第二步是每天检查vehicles表中添加的每辆车是否仍在网站上(可以删除或出售)。在这一步中,我将每个循环的车辆添加到daily_run_vehicle表中。 daily_run_vehicle的结构如下:

enter image description here

如果车辆存在,我会刮擦详细信息并更新vehiclesdata列,并将handled表中的daily_run_vehicle列设置为TRUE。如果已售出或删除,那么我会在retries表的daily_run_vehicle列中递增。

第二步应该每天运行。

首先,我循环访问vehicles表中的handled列为TRUE或daily_run_vehicle为False而是{{1 }}为5以上。对于每次迭代,我都会向handled表中添加一条新记录。

操作为retries,代码如下:

daily_run_vehicle

prepare-get-vehicles函数如下:

import json
import requests
from common.db import add_logs, get_vehicle_references
from common.db import capture_error
from common.common import APIHOST, NAMESPACE, USER_PASS


def execute_reference(reference, reference_url):
    action = "prepare-get-vehicle"
    url = APIHOST + "/api/v1/namespaces/" + NAMESPACE + "/actions/" + action
    response = requests.post(url,
                             data=json.dumps({"reference": reference, 'reference_url': reference_url}),
                             params={"blocking": "false"},
                             auth=(USER_PASS[0], USER_PASS[1]),
                             headers={"Content-Type": "application/json"})
    print(response.json())


def main(params):
    try:
        for reference in get_vehicle_references():
            execute_reference(reference[0], reference[1])

        return {"Success": "prepare-get-vehicles action executed successfully."}
    except Exception as e:
        capture_error(str(e))
        return {"Failure": "prepare-get-vehicles action NOT executed successfully."}

get_vehicle_references操作除了向def get_vehicle_references(): conn = db_connection() cur = conn.cursor() try: s = "SELECT reference, reference_url FROM vehicles v WHERE (NOT EXISTS (select reference from daily_run_vehicle WHERE (handled = %s or (handled = %s and retries >= %s)) AND reference = v.reference))" cur.execute(s, (True, False, 5)) return cur.fetchall() except Exception as e: capture_error(str(e)) conn.close() 表中添加新记录外,什么都不做,如下所示:

prepare-get-vehicle

但是问题在于daily_run_vehicle表具有超过30万条记录,并且每天都在变得越来越大。与def main(params): try: insert_daily_run_vehicle(params.get("reference", None), params.get("reference_url", None)) return {"Success.": "The DB filler (daily_run_vehicle) is successfully executed."} except Exception as e: capture_error(str(e)) return {"Failure": "The DB filler (daily_run_vehicle) action NOT executed successfully."} 中的for循环相比,在IBM Cloud上执行需要花费更多时间。超时为600秒,但是for循环需要更多时间。

有什么建议可以解决我的问题,以及如何遍历具有30万条记录的表,并为每条记录向vehicles添加新行?

谢谢。

2 个答案:

答案 0 :(得分:0)

如果车辆的ID不变,则可以执行以下操作:

INSERT INTO vehicle (id, reference, ...etc...) VALUES (1, 'ref', ...etc...) ON CONFLICT DO NOTHING;

要插入而不在现有行上循环。您甚至可以对冲突http://www.postgresqltutorial.com/postgresql-upsert/

进行更新

答案 1 :(得分:0)

要处理大型表db,您可以分批读取表行,每个批处理以编程方式运行一个新动作,每个动作可以并行运行,每个动作最多600s。

例如,如果您有一个300k的表,则以一定顺序遍历表行,例如每批100k。然后,您可以以编程方式并行调用3个动作,每个动作处理每批100k。