2012-05-01 92 views
0

我注意到我的mysql插入非常緩慢。爲了測試和演示,我用下面的表格:非常慢Innodb插入:65secs爲空表中的1K條目

+----------+-----------------------------------------------+ 
| Table | Create Table         | 
+----------+-----------------------------------------------+ 
| ik_b64_8 | CREATE TABLE `incr_tbl` (
    `cnt` int(11) NOT NULL, 
    PRIMARY KEY (`cnt`) 
) ENGINE=InnoDB DEFAULT CHARSET=ascii COLLATE=ascii_bin | 
+----------+-----------------------------------------------+ 

和Python代碼:

def profile_basic(cnt): 
    db = database.Connection("localhost","testing_delme","root", "") 
    t1 = time.time() 
    for ii in range(cnt): 
     db.execute("INSERT INTO testing_delme.incr_tbl VALUES (%s)", ii) 
    print time.time() - t1 

當我運行此插入只在空表上的代碼,它消耗了65秒爲1K插入。我有innodb_flush_log_at_trx_commit = 1,我需要這些,因爲表格不能丟失任何數據。我的問題是,使用這套裝置,插入物會變得如此緩慢嗎?還是我錯過了別的東西?

+0

您是否嘗試過使用一個單獨的語句將它們全部? – jeremyharris

+0

開始交易;插入foo(c1)值(v1),(v2),(v3);承諾; –

+0

我沒有在實際表格中嘗試過交易(以上僅用於演示)我一次只能插入1個條目。它將位於網絡服務器後面並捕獲用戶註冊。因此,這將無濟於事。但是,如果這提供了任何線索,我可以在這張桌子上試用它並讓你知道。 – Ethan

回答

1

「不能丟失任何數據。」這只是一個程度問題。如果不刷新,可能會丟失最後一秒的數據。隨着臉紅,你可能只會失去當時正在寫的東西。你真的想要大幅度的表現嗎?另外,如果你的磁盤發生故障,你將會丟失自上次備份以來的所有數據,這從長遠來看是不可避免的,並且涉及更多的數據,所以我更擔心頻繁備份。

禁用沖洗。我認爲,由於所有的磁盤活動,每插入一次,即使不是幾百毫秒,也會輕鬆達到幾十毫秒。桌上有幾個索引會使它更糟糕。

如果儘管如此,您絕對必須在每次寫入時刷新,如果將數據庫放在SSD上,也會顯着提高性能。

+0

我關心的表格存儲訂單信息。正如你所說,最壞的情況下,我鬆了1插入。我的問題是:每插入一次真的需要65ms,還是有其他因素(除了innodb_flush_log_at_trx_commit)我錯過了嗎? – Ethan

+0

好吧,試試關閉innodb_flush_log_at_trx_commit,看看它有多大的差異。 – Thomas

+0

是的,我曾試過。 innodb_flush_log_at_trx_commit = 2 - > 140ms/1K插入。將其設置爲0需要109ms。我還設置了innodb_file_per_table,它將上述值稍微降低到123ms和109ms。 – Ethan

0

我認爲你達到了每秒交易次數的限制。每個插入都被視爲單獨的事務,您必須處於自動提交模式。

(1)插入許多行,在一個SQL語句,你真行:

insert into incr_tbl values (1),(2),(3).... 

的Python相當於是這樣的:

db.execute("insert into incr_tbl values %s" % ",".join(["(%s)" % i for i in range(xx)])) 

(2)您也可以啓動交易明確:

db = ...(autocommit=False) 
db.begin_transaction() 
for i in xx: db.execute(... insert i ...) 
db.commit() 

如果你有一個像樣的服務器,你TX率應該是非常非常喜高於15秒,所以檢查你的機器和MySQL設置。即使你提交到磁盤並且每次都等待(sqlite),你應該在商品硬盤上達到100 tx/s。當數據庫位於USB閃存時,我只看到這個比率很低。另一個可能的解釋是你的python距離數據庫很遠,網絡延遲殺死了性能,在這種情況下(1)有幫助,(2)不會。

0

隨着db.execute()你插入一個接一個,它會很慢。使用循環建立一個清單,然後做一個批量插入即db.executemany()

def profile_basic(cnt): 
    import mysql.connector, time 
    cnx = mysql.connector.connect("localhost","testing_delme","root", "") 
    db = cnx.cursor() 
    list_ii = [] 
    t1 = time.time() 
    for ii in range(cnt): 
     list_ii.append(ii) 
    # One bulk insert 
    db.executemany("INSERT INTO testing_delme.incr_tbl VALUES (%s)", list_ii) 
    # Don't forget to commit 
    db.commit() 
    print time.time() - t1 
+0

它已經很長了,但我認爲我的情況是配置插入,就像插入一個新的用戶註冊到webapp。我認爲我處於自動提交模式,默認使用我正在使用的torndb。除了刪除自動提交和使用事務,有沒有其他的MySQL配置,我應該更好地調整插入性能? – Ethan

+0

即使使用autocommit = False,然後在循環後執行db.execute()並使用db.commit(),代碼將逐個添加,然後全部提交。我不得不添加60萬個插入,並且每100個插入需要10秒(幾乎整整一天)然後我查看它並將其更改爲db.executemany(),並且它在一分鐘內完成了所有600k插入。 – Delicious

+0

關於你的評論「在新用戶註冊時插入」,你在標題中的表現是每秒插入65s,因此每秒大約15個插入。如果您的用戶數多於每秒鐘,我會緩存新的註冊,然後使用executemany()進行批量插入。爲了緩存谷歌「memcached」 – Delicious