數據庫訂正腳本性能優化兩則:去除沒必要要的查詢和批量插入SQL

 

      最近在作多數據庫合併的腳本, 要將多個分數據庫的表數據合併到一個主數據庫中。 如下是我在編寫數據訂正腳本時犯過的錯誤, 記錄覺得鑑。程序員

 

       沒必要要的查詢sql

       請看如下語句:     數據庫

    regiondb = db.Houyiregiondb()
    houyidb = db.Houyidb(read_only=False)

    regiondbRet = regiondb.query(vmmacsFromRegiondbSql)
    houyidbRet = houyidb.query(vmmacsFromHouyidbSql)

    if len(regiondbRet) == 0:
        return

        原意很明顯, 是爲了分別取出 houyidb 和 houyiregiondb 相應的記錄, 用於後續對比。 可是這裏不假思索地將 houyidb 查詢的語句提早了, 結果可能致使  houyidb.query(vmmacsFromHouyidbSql) 成爲沒必要要的查詢。若是這個查詢會拉取不少數據的話, 就會形成很大浪費。 字節就是錢啊! 現在的程序員或許不用像之前的程序員那麼「摳門」, 也要「精打細算」 纔是。 修復辦法很簡單, 調換下語句順序便可:併發

          

    regiondb = db.Houyiregiondb()
    regiondbRet = regiondb.query(vmmacsFromRegiondbSql)
    if len(regiondbRet) == 0:
        regiondb.close()
        return

    houyidb = db.Houyidb(read_only=False)
    houyidbRet = houyidb.query(vmmacsFromHouyidbSql)

        教訓:  寫程序切忌不假思索。app

 

         鎖超時ide

      併發操做主數據庫時, 報 Lock wait timeout exceeded; try restarting transaction  鎖超時錯誤。
經查, 是由於insert X 表的時候同時併發 delete from X where ... 。 insert 在先, delete X 語句等待鎖。 因爲 insert X 要插入十幾萬條記錄, 耗費超過1分鐘, 而 innodb_lock_wait_timeout = 50s ( show variables like "%timeout%";) 所以 delete X 無可挽回地失敗了。 若是要復現問題的話,也很簡單: 先開始 insert X 大量記錄, 而後立刻敲入 delete X 語句, 等待 50s 後就會報出上述錯誤。
這裏須要優化 sql 語句。 優化的辦法是: 將 十幾萬條記錄切分紅屢次提交, 每次提交 1000 條插入語句。代碼以下:
def divideIntoGroups(allTuples, numPerGroup=1000):
    '''
       divide tuples into group of tuples ;
       each group has no more than numPerGroup tuples
       default value of numPerGroup is 1000
    '''
    groups = []
    totalNum = len(allTuples)
    if totalNum <= numPerGroup:
        groups.append(allTuples)
        return groups
    start = 0
    eachEnd = start + numPerGroup
    while start < totalNum:
        groups.append(allTuples[start:eachEnd])
        start += numPerGroup
        eachEnd = start + numPerGroup
        if eachEnd >= totalNum:
            eachEnd = totalNum
    return groups

def insertManyMany(insertSql, allTuples, db):
    '''
       insert many many records , usually more than 10000
       insert 1000 once and insert (len/1000+1) times
    '''
    groups = divideIntoGroups(allTuples)
    count = 0
    for groupTuples in groups:
        affectRows = db.executemany(insertSql, groupTuples)
        if affectRows:
            count += affectRows
        db.commit()
    needInsertNum = len(allTuples)
    isPassedMsg = ('OK' if needInsertNum==count else 'SOME ERROR')
    printAndLog("Need insert %d records, and actual %d. %s" % (needInsertNum, count, isPassedMsg))
 

      調用方法以下:優化

      insertSql = "insert into student (name, age) value (%s, %s) "spa

      allTuples = [("zhang", 20), ("qian", 25), ("wang", 23), ... , ("liu", 26)]rest

      insertManyMany(insertSql, allTuples, db)code

 效果很明顯。 原來插入 32000 條記錄須要 18s, 如今只須要 2-3s , 原來插入 129968 條記錄須要 67s , 如今只須要 12-15s. 同時, 每次提交的插入事務變短, 能夠減小鎖等待時間。
相關文章
相關標籤/搜索