2010-05-21 49 views
1

編輯:澄清最初來自平面文件數據庫的記錄,但不在MySQL數據庫中。檢查和插入記錄的最佳方法

在我們現有的C程序中的一個,其目的是從該平面文件中的數據並將它們(基於標準)插入到MySQL表:從sql_table甲

Open connection to MySQL DB 
for record in all_record_of_my_flat_file: 
    if record contain a certain field: 
    if record is NOT in sql_table A: // see #1 
     insert record information into sql_table A and B // see #2 
Close connection to MySQL DB 
  1. 選擇字段其中場= XXX
  2. 2個插入

我相信管理層也沒覺得這是值得添加的功能,這樣,當在平板音響領域le被創建,它會被插入到數據庫中。這是特定於一個客戶(我知道)。我也覺得奇怪,我們使用這種工具來「同步」數據。我被賦予使用和維護這個腳本的責任,所以我沒有太多的瞭解整個過程。目的是主要處理額外的記錄,所以這不是第一次使用它。

這通常每X個月進行一次,以便將所有內容同步或告訴我。我也被告知這個過程大概需要幾天。目前有(最多)250萬條記錄(儘管不一定所有的2.5米都會被插入,而且最有可能少得多)。其中一個表格包含10個字段和另外5個字段。關於遍歷記錄沒有太多的工作要做,因爲那一部分目前不能改變。我想要做的是加速查詢MySQL的部分。

我不確定我是否遺漏了任何重要細節 - 請讓我知道!我也沒有SQL專家,所以隨時指出明顯的。

我想過:

  1. 將所有插入到一個事務(目前我不知道它是多麼的重要,該交易將全部或無,或者如果這會影響性能)
  2. 使用插入X其中NOT EXISTSŸ
  3. LOAD DATA INFILE(但這需要我創建了一個(可能)大型臨時文件)

,我讀了(希望有人能確認)我應該放棄索引,所以他們不重新計算。

mysql Ver 14.7 Distrib 4.1.22, for sun-solaris2.10 (sparc) using readline 4.3

回答

0

我與其他同事討論,這裏是一些改進,我們想出了:

爲:

SELECT X FROM TABLE_A WHERE Y=Z; 

更改爲(目前正在等待驗證X上是否始終ü尼克):

SELECT X FROM TABLE_A WHERE X=Z LIMIT 1; 

這是一個簡單的改變,我們看到了一些微小的改進。我無法真正量化它,但我做到了:

SELECT X FROM TABLE_A ORDER BY RAND() LIMIT 1 

並比較了前兩個查詢。對於少數測試,大約有0.1秒的改進。也許它緩存了一些東西,但LIMIT 1應該有所幫助。

然後另一個(尚未實施)改進(?):

for record number X in entire record range: 
    if (no CACHE) 
    CACHE = retrieve Y records (sequentially) from the database 
    if (X exceeds the highest record number in cache) 
    CACHE = retrieve the next set of Y records (sequentially) from the database 
    search for record number X in CACHE 
    ...etc 

我不知道如何設置Y到,是否有確定哪些是一個很好的大小號碼嘗試用任何方法?該表有200k條目。當我完成實施時,我會編輯一些結果。

1

這裏是我的想法在你的程序腳本...

1)僅僅是一個很好的做法,無論如何,我會做到這一點不管。

2)可以爲您節省大量的執行時間。如果您可以在不使用C程序迭代的情況下直接解決問題,這可以節省相當長的時間。您必須首先對其進行配置,以確保它在測試環境中真正實現。

3)LOAD DATA INFILE是插入大量數據時使用的一種策略。如果你有很多記錄要插入(我會寫一個查詢來做一個分析來找出你需要插入到表B中的記錄數),那麼你可能會用這種方法加載它們。

在插入之前刪除索引可以有助於減少運行時間,但是您需要確保在完成後將其還原。

雖然......爲什麼表B中的記錄並不是全部?您沒有提及處理的工作原理,但我認爲確保(在您的應用程序中)記錄在沒有您的服務腳本干預的情況下到達那裏將是有利的。當然,你比我更瞭解你的情況,所以如果它不在基地,請忽略此段。我從經驗中知道,爲什麼需要存在實用程序清理腳本的原因很多。


編輯:讀您的修改後的文章後,您的問題域發生了變化:你有你需要加載到基於特定標準的數據庫(搜索?)平面文件了一系列的記錄。我認爲,招儘快這樣做是爲了確定在C應用程序實際上是最慢,花費時間最多的紡紗其衆所周知的車輪:

  • 如果它讀取從磁盤,你就完蛋了,除非獲得更快的磁盤,否則你無法做任何事情。
  • 如果它做的SQL查詢,插入操作,你可以嘗試優化這一點,但傻冒做兩個數據庫(平面文件和MySQL的一個)

快速思想之間的比較:通過做一個LOAD DATA INFILE批量插入可以非常快速地填充一個臨時表(如果MySQL允許的話,甚至可能是內存表),然後執行INSERT IF NOT EXISTS可能會比現在做的更快。

簡而言之,請進行剖析,並找出放緩的地方。除此之外,請與經驗豐富的DBA討論如何做好這一點的提示。

+0

有大約2.5mil記錄(但不是全部)。我可以使用腳本來調用我們的工具,並進行一些字符串解析,但我認爲它會是相同的(如果不是更慢)。我將嘗試澄清問題中的其他問題。 – nevets1219 2010-05-21 19:03:44

1

爲什麼不將MySQL服務器升級到5.0(或5.1),然後使用觸發器,以便它始終保持最新狀態(無需每月腳本)?

DELIMITER // 
CREATE TRIGGER insert_into_a AFTER INSERT ON source_table 
FOR EACH ROW 
BEGIN 
    IF NEW.foo > 1 THEN 
     SELECT id AS @testvar FROM a WHERE a.id = NEW.id; 
     IF @testvar != NEW.id THEN 
      INSERT INTO a (col1, col2) VALUES (NEW.col1, NEW.col2); 
      INSERT INTO b (col1, col2) VALUES (NEW.col1, NEW.col2); 
     END IF 
    END IF 
END // 
DELIMITER ; 

然後,你甚至可以設置更新和刪除觸發器,這樣的表始終保持同步(如果源表COL1被更新,它會自動傳播到A和B)...

+0

我對不清楚的原因表示歉意,正在處理的原始數據不在數據庫中(它是一個平面文件),所以我不確定我可以使用這種方法。 – nevets1219 2010-05-21 19:10:45

+0

夠公平的。那麼這根本不可能...... – ircmaxell 2010-05-21 19:24:35

+0

其實,現在我想到了......創建一個臨時表,添加這個觸發器,然後執行一個'LOAD DATA INFILE' ...所有的「開銷」都保留下來正確的數據庫,所以你節省了網絡和解析開銷... – ircmaxell 2010-05-21 19:54:14

相關問題