Mysql

為這些項目需求選擇 MyISAM 而不是 InnoDB;和長期選擇

  • July 3, 2014

很抱歉這篇文章很長,但我必須提供盡可能多的資訊才能使這個非常模糊的問題更加具體。

我的項目的目的是讓使用者搜尋各種產品的(巨大的)數據庫。

  • 每個產品都存在於一個類別下。
  • 每個產品將有 10 到 100 個“規格”或“功能”供使用者搜尋。

最常見的案例是:

  1. 使用者點擊一個類別;然後根據需要點擊各種子類別。
  2. 使用者從 1 或 2 個條件開始並蒐索產品。
  3. 然後,使用者不斷在搜尋中添加更多條件以縮小產品範圍。

我有三個主表“產品”、“功能列舉”和“功能”。讓數據輸入使用者為產品動態創建新的“功能”非常重要——因此我使用的是 EAV(反)模式。

以下是表的結構:

'products'
   ID(PK), TITLE, CATEGORY
   (Indexed by CATEGORY)
'features_enum'
   ID(PK), TITLE
'features'
   P_ID, F_ID, VAL
   (Indexed by P_ID and then F_ID)

我的主要搜尋查詢的範例格式:

SELECT
 p.ID,
 p.TITLE PROD_TITLE,
 fe.TITLE FEATURE_TITLE,
 f.VAL
FROM
 products p, features f, features_enum fe
WHERE
 p.CATEGORY = 57 AND
 p.ID = f.P_ID AND
 f.F_ID = fe.ID AND
 (
   (f.F_ID  = 1 AND f.VAL = 'Val1') AND
   (f.F_ID  = 2 AND f.VAL = 'Val2') AND
   ...
   (f.F_ID  = N AND f.VAL = 'ValN') AND
 )

到目前為止我的實驗:

由於我在數據庫方面的知識和經驗有限,我在理論規劃上碰壁了。所以,我生成了大量的測試數據來簡單地看看什麼會起作用。所有三個表都有 500,000 個測試行。這裡是平均值。主要搜尋查詢的執行時間:

  1. 沒有索引的 InnoDB:90 年代。
  2. 帶索引的 InnoDB:15 秒。 緩衝池大小增加後 0.3 秒
  3. 沒有索引的 MyISAM:9s。
  4. 帶索引的 MyISAM:0.7 秒。
  5. MyISAM 索引 + FIXED 行類型:0.16s。

測試機 - Pentium 4 1.9GHz,1.5GB RAM,IDE HDD,Win7。

除了索引之外,我基本上沒有做任何優化。所以我可能錯過了很多事情,這些事情本來可以讓 InnoDB 執行得更快。**InnoDB 緩衝池大小設置為 16M (!!);我將其增加到 128M。現在,InnoDB 真的很快。所以我傾向於 MyISAM 的一個重要原因現在已經消失了。**也許還有更多我可以做的。

關於該項目的一些要點和長期使用估計:

  • 每天添加 20 種新產品,大約每天 20 x 100’specs’ = 2000 條記錄寫入。
  • 1,000,000 次頁面訪問,在最壞的情況下 - 每天執行相同數量的搜尋查詢。
  • 這些表的總記錄數預計將達到 5,000,000 條。
  • 寫入將由半受控制的一群人進行,其中讀取是公開的。
  • 沒有復雜的“事務”類型寫入。我現在能想到的最複雜的寫法是——

$$ one product row + 100 feature rows max $$- 一口氣

  • 只需要幾個約束,但如果需要選擇 MyISAM,我可以在應用程序級別本身強制執行它們。
  • 來自應用程序其他部分的數據庫訪問 - 使用者註冊、身份驗證等.. 將很少而且介於兩者之間,我認為它們不會有太大影響。

鑑於所有這些,我偏向於 MyISAM。但是我需要已經有 MySQL 經驗的人的意見。

問題:

  1. 如果 InnoDB 執行時間錯誤/令人驚訝,我在測試中錯過了什麼?增加緩衝池大小會顯著提高性能。往上看。
  2. 如果不是,考慮到以上所有因素,從長遠來看,MyISAM 真的是不錯的選擇嗎?
  3. 如果後來發現 MyISAM 也是一個糟糕的選擇,那麼我如何輕鬆地重構數據庫?我有什麼選擇?

附帶說明:

  1. 如果選擇 EAV 不好,我可以為這個項目使用什麼其他架構?

InnoDB 和 MyISAM 各有優缺點。

如果你有足夠的 RAM,我會選擇 InnoDB,因為它在 Buffer Pool 中記憶體數據和索引頁面。MyISAM 只在 Key Cache 中記憶體索引頁。

MyISAM 表在每次 INSERT、UPDATE 和 DELETE 時都會遇到全表鎖。MyISAM 表總是需要對數據進行磁碟訪問。

InnoDB 表總是在以下區域產生磁碟 I/O:

  • 雙寫緩衝區:更改發佈在 ibdata1 以避免作業系統記憶體

  • 插入緩衝區:對 ibdata1 中發布的輔助(非唯一)索引的更改

  • 數據和索引

    • 在 innodb_file_per_table = 0 時,將更改寫入 ibdata1
    • 使用 innodb_file_per_table = 1,更改將寫入.ibd表空間文件。仍然需要針對 ibdata1 讀取 I/O 以交叉檢查表元數據

概括

在具有以下條件的環境中:

  • 大量寫入
  • 重讀
  • 大量記憶體
  • 重連接

我總是會選擇 InnoDB。請查看我關於 InnoDB over MyISAM 的另一篇文章:何時從 MyISAM 切換到 InnoDB?

我什麼時候會選擇 MyISAM?

在以下場景下

  • 使用 MySQL 複製
  • 掌握所有 InnoDB
  • 所有表都轉換為 MyISAM 的從站
  • ALTER TABLE ... ROW_FORMAT=Fixed對於 Slave 上的所有表

在磁碟 I/O 方面,MyISAM 稍有優勢,ROW_FORMAT-Fixed因為您只與一個文件互動,即.MYD文件。行大小是完全可預測的,因為 VARCHAR 被視為 CHAR,這縮短了數據檢索的訪問時間。

另一方面,InnoDB 必須與多個文件互動(ibdata1,InnoDB 表的 .ibd 上的多個讀/寫執行緒)。

根據我使用 MySQL 的經驗,MyIsam 的插入和讀取速度非常快。另一方面,如果您有許多使用者同時訪問數據庫插入和查詢數據,您將開始看到 MyIsam 的性能急劇下降。

MyIsam 在以下情況下很好:

  • 你有很多寫和很少讀
  • 你有很多讀取和很少寫入
  • 你有一個部落格。大多數時候,每天只有少數人在文章和評論之間寫文章

MyIsam 在以下情況下很糟糕:

  • 你有很多讀取和寫入同時發生

我已經測試了 PostGreSQL,當數據庫因同時發生讀取和寫入而受到嚴重打擊時,它會執行 MySQL MyIsam。此外,當您擁有高流量網站時,MyIsam 往往每月至少會損壞一次。

引用自:https://dba.stackexchange.com/questions/24951