之前測試cobar的效率,因為cobar不支持存儲過程,所以需要應用程序插入數據,jdbc不靈活,用Python的MySQLdb模塊可以實現。
開始測試的時候用單條insert語句循環n次,最后commit,結果慢的要死,插一萬條用了兩分鍾,十萬條我去吃了個飯回來還在插。十萬條用存儲過程插單庫也用了50多秒。
從UC的這篇文章學習了一些SQL優化的知識。
主要有三條:
1、insert的時候盡量多條一起插,不要單條插。這樣可以減少日志量,降低日志刷盤數據量和頻率,效率提高很多。
這是文章提供的測試對比:
2、在事務中進行插入。也就是每次部分commit,否則每條insert commit 創建事務的消耗也是不小的。
3、 數據插入的時候保持有序。比如Innodb用的是B+樹索引,對B+樹的插入如果是在索引中間就會需要樹節點分裂合並,這也會有一定的消耗。
幾種方法綜合起來的測試數據如下:
可以看到1000萬以下數據的優化效果是明顯的,但是單合並數據+事務的方式在1000萬以上性能會有急劇下降,因為此時已經達到了innodb_buffer的上限,隨機插入每次需要大量的磁盤操作,性能下降明顯。而有序插入在1000萬以上時也表現穩定,因為索引定位方便,不需要頻繁對磁盤讀寫,維持較高性能。
據此修改了Python程序:
import MySQLdb
db=MySQLdb.connect(host='127.0.0.1', user='test', passwd='test', port=8066)
cur=db.cursor()
cur.execute('use dbtest')
cur.execute('truncate table tb5')
for t in range(0,100):
sql = 'insert into tb5 (id, val) values '
for i in range(1,100000):
sql += ' ('+`t*100000+i`+', "tb5EXTRA"),'
sql += ' ('+`t`+'00000, "tb5EXTRA")'
cur.execute(sql)
db.commit()
cur.close()
db.close()
共插入了1000萬條數據,sublime顯示用了333.3s,比之前插入10萬條都減少了很多,測試插10萬條只需要3s。
15個分庫每個60十多萬條。
- 過程中有個問題,開始我的sql變量是連接所有插入條目的,但是16節點的cobar在輸100萬條的時候就連接斷開了,而單庫直接10條也插不進去,顯示mysql連接斷開。
這個是sql語句長度限制的問題,在mysql的配置文件中有一個max_allowed_packet = 1M
,10萬條插入語句已經超過這個限額了,100萬條分給16個cobar節點也超過了,所以可以把這個參數調大,或者代碼里分段執行sql。
- 還有一個問題是事務大小的問題,
innodb_log_buffer_size
參數決定這個,超限的話數據會寫入磁盤,從而導致效率下滑,所以事務提交也不能攢得太大。