使用python遍歷mysql中有千萬行數(shù)據(jù)的大表

最近工作中遇到了一個問題:將mysql的數(shù)據(jù)同步到elasticsearch中,現(xiàn)在有很多方案, logstash-jdbcelasticsearch-jdbcgo-mysql-elasticsearch,本來原來是使用logstash-jdbc的,但是由于其配置文件是基于ruby語法的,導(dǎo)致遇到問題需要查很多資料,加上logstash調(diào)試困難(很可能是我用的姿勢不對。。。),所以決定手動在elasticsearch中建表,然后寫腳本定期更新數(shù)據(jù),那么問題就來了:第一次插入需要一次性插入以前的所有數(shù)據(jù),以前使用pymysql時用的都是DictCursor游標,原理是一次性講數(shù)據(jù)加載到內(nèi)存中,但是現(xiàn)有表中有幾張有數(shù)千萬行,幾個G大小,一次性讀到內(nèi)存中很不明智,google后,發(fā)現(xiàn)一篇blog不錯,翻譯共享一下(渣英語,不要笑,原文鏈接在文末)。

當(dāng)使用sql查詢的結(jié)果有非常多行時,如果使用默認的cursor,你的程序在接受數(shù)據(jù)的的時候很可能卡住或者被殺死,原因是mysql客戶端(Java,Pyhton)默認在內(nèi)存里緩存下所有行然后再處理,如果內(nèi)存溢出后,你的程序就會被殺死。

解決方式是實用流式游標,在Python中,你可以使用pymysql.cursors.SSCursor(或者SSDictCursor)來解決這個問題

import pymysql
conn = pymysql.connect(...)
cursor = pymysql.cursors.SSCursor(conn)
cursor.execute(...)
while True:
    row = cursor.fetchone()
    if not row:
        break
    ...

這里有兩點需要注意下:

  1. 使用pymysql.cursors.SSCursor代替默認的cursor。可以使用以上代碼,或者這樣寫:conn.cursor(pymysql.cursors.SSCursor)
  2. 使用fetchone去每次只獲得一行,別使用fetchall。也可以使用fetchmay,但是這樣其實是多次調(diào)用fetchone。

對于SSCursor有一個錯誤的理解,就是SSCursor是服務(wù)端一次性讀出所有數(shù)據(jù)然后一條一條返給客戶端,其實不是這樣的,這個cursor實際上沒有緩存下來任何數(shù)據(jù),它不會讀取所有所有到內(nèi)存中,它的做法是從儲存塊中讀取記錄,并且一條一條返回給你。這里有一個更適合的名字:流式游標。

因為SSCursor是沒有緩存的游標,這里有幾條約束:

  1. 這個connection只能讀完所有行之后才能處理其他sql。如果你需要并行執(zhí)行sql,在另外一個connection中執(zhí)行,否則你會遇到 error 2014 , "Commands out of sync; you can't run this command now."
  2. 必須一次性讀完所有行,每次讀取后處理數(shù)據(jù)要快,不能超過60s,否則mysql將會斷開這次連接( error2013 , “Lost connection to MySQL server during query),也可以修改 SET NET_WRITE_TIMEOUT = xx 來增加超時間隔。

參考:Techualization: Retrieving million of rows from MySQL(原文更加詳細)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,754評論 18 399
  • 本人陸陸續(xù)續(xù)接觸了ELK的1.4,2.0,2.4,5.0,5.2版本,可以說前面使用當(dāng)中一直沒有太多感觸,最近使用...
    三杯水Plus閱讀 4,118評論 0 12
  • JDBC概述 在Java中,數(shù)據(jù)庫存取技術(shù)可分為如下幾類:JDBC直接訪問數(shù)據(jù)庫、JDO技術(shù)、第三方O/R工具,如...
    usopp閱讀 3,551評論 3 75
  • MySQL遠程登錄 MySQL MAC5.7.17及以上版本中文顯示亂碼問題 若編碼信息如圖,則無需設(shè)置。若dat...
    PengFly閱讀 768評論 0 0
  • 今年是女兒的最后一個六一兒童節(jié),明年就走進初中生的行列了。想想竟然有種心酸的感覺呢。孩子就這樣長大了! 六一兒童節(jié)...
    愛閱沈陽閱讀 256評論 0 0