pymysql 讀取大數據內存卡死的解決方案

背景:目前表中只有5G(後期持續增加),可是其中一個字段(如下稱爲detail字段)存了2M(不必定2M,部分爲0,平均下來就是2M),字段中存的是一個數組,數組中存N個json數據。這個字段以下:python

[{"A": "A", "B": "B", "C": "C", "D": "D"}...]

要是拆表的話,可能要拆好多個,要是存多行根據阿里巴巴《Java 開發手冊》提出單錶行數超過 500 萬行,也不是很建議。但願有大佬能指教一下。
回到正題,一開始是分兩個表存儲,一個表存基本信息(A表),一個表(B表)存關聯字段,及detail字段。貌似沒有啥用,按需求現要將兩張表合在一塊兒供BI去處理。直接複製了那張基礎字段的A表,經過遍歷B表根據關聯字段進行更新。可是在select的時候內存讀入的數據太大直接卡死(狗頭)。因而在網上查找如何經過pymysql處理大數據的問題。解決方案以下:mysql

1.經過limit分批次讀取數據進行操做:

import pymysql

up_db = pymysql.connections.Connection(host=MYSQL_HOST,
                               port=MYSQL_PORT,
                               user=MYSQL_USER,
                               password=MYSQL_PASSWORD,
                               db=MYSQL_DB,
                               charset='utf8mb4',)
                               

count = 0
while True:
    # if count == 2:
    #     break

    select_sql = "select sec_report_id,detail from sec_report_original_data_detail limit %s,2"%(count)
    up_cursor = up_db.cursor()
    up_cursor.execute(select_sql)
    result = up_cursor.fetchall()
    for data in result:
        sec_report_id = data[0]
        detail = data[1]
        update_sql = "update `sec_report_original_data_intact` set detail = '%s' where `sec_report_id` = '%s' " % (
        db.escape_string(detail), sec_report_id)
        print(update_sql)
        res = up_cursor.execute(update_sql)
        if res:
            print(res)
            up_db.commit()
            print(f'{sec_report_id}插入成功')

    count+=2

能夠解決問題,不過只是拿了幾條作測試(我用的是第二種),這裏沒寫終止條件,有朋友要用的話本身加上。sql

2.經過pymysql的SSCursor沒有緩存的遊標

pymysql.cursors.SSCursor代替默認的cursor會從數據庫中一條一條的讀取記錄,從而不會形成內存卡死,可是也有須要注意的地方:數據庫

  • 這個遊標對象只能讀完全部行以後才能處理其餘sql。若是你須要並行執行sql,須要從新生成一個鏈接
  • 必須一次性讀完全部行,每次讀取後處理數據要快,不能超過60s,不然mysql將會斷開此次鏈接(沒有遇到這個問題,遇到的能夠討論一下)
import pymysql

db = pymysql.connections.Connection(host=MYSQL_HOST,
                               port=MYSQL_PORT,
                               user=MYSQL_USER,
                               password=MYSQL_PASSWORD,
                               db=MYSQL_DB,
                               charset='utf8mb4',
                               cursorclass=pymysql.cursors.SSDictCursor)

up_db = pymysql.connections.Connection(host=MYSQL_HOST,
                               port=MYSQL_PORT,
                               user=MYSQL_USER,
                               password=MYSQL_PASSWORD,
                               db=MYSQL_DB,
                               charset='utf8mb4',)
                               
up_cursor = up_db.cursor()
cursor = pymysql.cursors.SSCursor(db)
select_sql = "select sec_report_id,detail from sec_report_original_data_detail"
cursor.execute(select_sql)
result = cursor.fetchone()

try:
    while result is not None:
        sec_report_id = result[0]
        detail = result[1]
        update_sql = "update `sec_report_original_data_intact` set detail = '%s' where `sec_report_id` = '%s'"%(db.escape_string(detail),sec_report_id)
        res = up_cursor.execute(update_sql)

        if res:
            print(res)
            up_db.commit()
            print(f'{sec_report_id}插入成功')
        result = cursor.fetchone()
except Exception as e:
    print(e)
finally:
    up_cursor.close()
    cursor.close()
    db.close()

解決了一次性讀取大數據的方法,可是沒找到特別好的存儲那個detail字段中數據的辦法,有朋友瞭解的能夠溝通一下。json

相關文章
相關標籤/搜索