從MySQL和MongoDB的對比,看SQL與NoSQL的較量

行情繫統提供的接口通過Redis獲取數據,目前使用Redis最多隻存儲了大概8000條左右的分鐘k的行情數據,考慮到將來可能會有更大數據量的查詢需求,需要查詢幾月甚至幾年的行情數據,要求數據庫在提供功能的同時又能保證性能和穩定性。Redis通常只用做較小數據量的內存數據庫,而傳統關係數據庫又有一定的查詢性能瓶頸,所以考慮調研一下其它的NoSQL數據庫。

一、為什麼調研MongoDB?

圖1-1是DB-Engines2017年11月數據庫的排名統計,可以看到MongoDB總排名在第5,在NoSQL數據庫中排名第1。

行情繫統提供的接口通過Redis獲取數據,目前使用Redis最多隻存儲了大概8000條左右的分鐘k的行情數據,考慮到將來可能會有更大數據量的查詢需求,需要查詢幾月甚至幾年的行情數據,要求數據庫在提供功能的同時又能保證性能和穩定性。Redis通常只用做較小數據量的內存數據庫,而傳統關係數據庫又有一定的查詢性能瓶頸,所以考慮調研一下其它的NoSQL數據庫。

一、為什麼調研MongoDB?

圖1-1是DB-Engines2017年11月數據庫的排名統計,可以看到MongoDB總排名在第5,在NoSQL數據庫中排名第1。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖1-1 DB-Engines2017年11月數據庫的排名統計

優點:

  • 社區活躍,用戶較多,應用廣泛

  • MongoDB在內存充足的情況下數據都放入內存且有完整的索引支持,查詢效率較高

  • MongoDB的分片機制,支持海量數據的存儲和擴展

缺點:

  • 不支持事務

  • 不支持join、複雜查詢

初步調研下來,MongoDB具備我們需要的特性,而缺點不影響應用場景,故接下來我們就開始做實際的性能壓測。

二、壓測性能對比

1、準備條件

(1)MySQL 、MongoDB數據庫所在服務器硬件環境

行情繫統提供的接口通過Redis獲取數據,目前使用Redis最多隻存儲了大概8000條左右的分鐘k的行情數據,考慮到將來可能會有更大數據量的查詢需求,需要查詢幾月甚至幾年的行情數據,要求數據庫在提供功能的同時又能保證性能和穩定性。Redis通常只用做較小數據量的內存數據庫,而傳統關係數據庫又有一定的查詢性能瓶頸,所以考慮調研一下其它的NoSQL數據庫。

一、為什麼調研MongoDB?

圖1-1是DB-Engines2017年11月數據庫的排名統計,可以看到MongoDB總排名在第5,在NoSQL數據庫中排名第1。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖1-1 DB-Engines2017年11月數據庫的排名統計

優點:

  • 社區活躍,用戶較多,應用廣泛

  • MongoDB在內存充足的情況下數據都放入內存且有完整的索引支持,查詢效率較高

  • MongoDB的分片機制,支持海量數據的存儲和擴展

缺點:

  • 不支持事務

  • 不支持join、複雜查詢

初步調研下來,MongoDB具備我們需要的特性,而缺點不影響應用場景,故接下來我們就開始做實際的性能壓測。

二、壓測性能對比

1、準備條件

(1)MySQL 、MongoDB數據庫所在服務器硬件環境

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-1 服務器硬件環境主要參數

(2)最新的數據庫版本

MongoDB server version: 3.4.5

MongoDB client version: mongo-java-driver-2.14.3

MySQL server version:5.6.34

MySQL connector version: MySQL-connector-java-6.0.6

MongoDB使用的儲存引擎wiredTiger

MySQL使用的儲存引擎InnoDB

(3)數據庫表結構及索引

MongoDB索引為dateTime 且是唯一索引。我們實際測試使用的MongoDB數據結構及字段如圖2-1所示。

行情繫統提供的接口通過Redis獲取數據,目前使用Redis最多隻存儲了大概8000條左右的分鐘k的行情數據,考慮到將來可能會有更大數據量的查詢需求,需要查詢幾月甚至幾年的行情數據,要求數據庫在提供功能的同時又能保證性能和穩定性。Redis通常只用做較小數據量的內存數據庫,而傳統關係數據庫又有一定的查詢性能瓶頸,所以考慮調研一下其它的NoSQL數據庫。

一、為什麼調研MongoDB?

圖1-1是DB-Engines2017年11月數據庫的排名統計,可以看到MongoDB總排名在第5,在NoSQL數據庫中排名第1。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖1-1 DB-Engines2017年11月數據庫的排名統計

優點:

  • 社區活躍,用戶較多,應用廣泛

  • MongoDB在內存充足的情況下數據都放入內存且有完整的索引支持,查詢效率較高

  • MongoDB的分片機制,支持海量數據的存儲和擴展

缺點:

  • 不支持事務

  • 不支持join、複雜查詢

初步調研下來,MongoDB具備我們需要的特性,而缺點不影響應用場景,故接下來我們就開始做實際的性能壓測。

二、壓測性能對比

1、準備條件

(1)MySQL 、MongoDB數據庫所在服務器硬件環境

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-1 服務器硬件環境主要參數

(2)最新的數據庫版本

MongoDB server version: 3.4.5

MongoDB client version: mongo-java-driver-2.14.3

MySQL server version:5.6.34

MySQL connector version: MySQL-connector-java-6.0.6

MongoDB使用的儲存引擎wiredTiger

MySQL使用的儲存引擎InnoDB

(3)數據庫表結構及索引

MongoDB索引為dateTime 且是唯一索引。我們實際測試使用的MongoDB數據結構及字段如圖2-1所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-1 MongoDB數據表記錄示例

MySQL索引為DATETIME,PARTNER_ID,GOODS_ID,SCOPE且是唯一索引。我們實際測試使用的MySQL數據結構及字段如圖2-2所示。

行情繫統提供的接口通過Redis獲取數據,目前使用Redis最多隻存儲了大概8000條左右的分鐘k的行情數據,考慮到將來可能會有更大數據量的查詢需求,需要查詢幾月甚至幾年的行情數據,要求數據庫在提供功能的同時又能保證性能和穩定性。Redis通常只用做較小數據量的內存數據庫,而傳統關係數據庫又有一定的查詢性能瓶頸,所以考慮調研一下其它的NoSQL數據庫。

一、為什麼調研MongoDB?

圖1-1是DB-Engines2017年11月數據庫的排名統計,可以看到MongoDB總排名在第5,在NoSQL數據庫中排名第1。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖1-1 DB-Engines2017年11月數據庫的排名統計

優點:

  • 社區活躍,用戶較多,應用廣泛

  • MongoDB在內存充足的情況下數據都放入內存且有完整的索引支持,查詢效率較高

  • MongoDB的分片機制,支持海量數據的存儲和擴展

缺點:

  • 不支持事務

  • 不支持join、複雜查詢

初步調研下來,MongoDB具備我們需要的特性,而缺點不影響應用場景,故接下來我們就開始做實際的性能壓測。

二、壓測性能對比

1、準備條件

(1)MySQL 、MongoDB數據庫所在服務器硬件環境

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-1 服務器硬件環境主要參數

(2)最新的數據庫版本

MongoDB server version: 3.4.5

MongoDB client version: mongo-java-driver-2.14.3

MySQL server version:5.6.34

MySQL connector version: MySQL-connector-java-6.0.6

MongoDB使用的儲存引擎wiredTiger

MySQL使用的儲存引擎InnoDB

(3)數據庫表結構及索引

MongoDB索引為dateTime 且是唯一索引。我們實際測試使用的MongoDB數據結構及字段如圖2-1所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-1 MongoDB數據表記錄示例

MySQL索引為DATETIME,PARTNER_ID,GOODS_ID,SCOPE且是唯一索引。我們實際測試使用的MySQL數據結構及字段如圖2-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-2 MySQL數據表記錄示例

SQL語句根據datetime字段進行時間範圍的查詢

(4)連接池最大連接數都設置為200個,SQL語句調到最優

2、百萬、千萬級別的下不同查詢量不同併發量的壓測結果

數據庫表中記錄數總量在百萬、千萬級別的壓測數據及結果如表2-2所示。

行情繫統提供的接口通過Redis獲取數據,目前使用Redis最多隻存儲了大概8000條左右的分鐘k的行情數據,考慮到將來可能會有更大數據量的查詢需求,需要查詢幾月甚至幾年的行情數據,要求數據庫在提供功能的同時又能保證性能和穩定性。Redis通常只用做較小數據量的內存數據庫,而傳統關係數據庫又有一定的查詢性能瓶頸,所以考慮調研一下其它的NoSQL數據庫。

一、為什麼調研MongoDB?

圖1-1是DB-Engines2017年11月數據庫的排名統計,可以看到MongoDB總排名在第5,在NoSQL數據庫中排名第1。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖1-1 DB-Engines2017年11月數據庫的排名統計

優點:

  • 社區活躍,用戶較多,應用廣泛

  • MongoDB在內存充足的情況下數據都放入內存且有完整的索引支持,查詢效率較高

  • MongoDB的分片機制,支持海量數據的存儲和擴展

缺點:

  • 不支持事務

  • 不支持join、複雜查詢

初步調研下來,MongoDB具備我們需要的特性,而缺點不影響應用場景,故接下來我們就開始做實際的性能壓測。

二、壓測性能對比

1、準備條件

(1)MySQL 、MongoDB數據庫所在服務器硬件環境

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-1 服務器硬件環境主要參數

(2)最新的數據庫版本

MongoDB server version: 3.4.5

MongoDB client version: mongo-java-driver-2.14.3

MySQL server version:5.6.34

MySQL connector version: MySQL-connector-java-6.0.6

MongoDB使用的儲存引擎wiredTiger

MySQL使用的儲存引擎InnoDB

(3)數據庫表結構及索引

MongoDB索引為dateTime 且是唯一索引。我們實際測試使用的MongoDB數據結構及字段如圖2-1所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-1 MongoDB數據表記錄示例

MySQL索引為DATETIME,PARTNER_ID,GOODS_ID,SCOPE且是唯一索引。我們實際測試使用的MySQL數據結構及字段如圖2-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-2 MySQL數據表記錄示例

SQL語句根據datetime字段進行時間範圍的查詢

(4)連接池最大連接數都設置為200個,SQL語句調到最優

2、百萬、千萬級別的下不同查詢量不同併發量的壓測結果

數據庫表中記錄數總量在百萬、千萬級別的壓測數據及結果如表2-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-2 百萬、千萬級別的壓測數據及結果

3、億級別的下不同查詢量不同併發量的壓測結果

數據庫表中記錄數總量在億級別的壓測數據及結果如表2-3所示。

行情繫統提供的接口通過Redis獲取數據,目前使用Redis最多隻存儲了大概8000條左右的分鐘k的行情數據,考慮到將來可能會有更大數據量的查詢需求,需要查詢幾月甚至幾年的行情數據,要求數據庫在提供功能的同時又能保證性能和穩定性。Redis通常只用做較小數據量的內存數據庫,而傳統關係數據庫又有一定的查詢性能瓶頸,所以考慮調研一下其它的NoSQL數據庫。

一、為什麼調研MongoDB?

圖1-1是DB-Engines2017年11月數據庫的排名統計,可以看到MongoDB總排名在第5,在NoSQL數據庫中排名第1。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖1-1 DB-Engines2017年11月數據庫的排名統計

優點:

  • 社區活躍,用戶較多,應用廣泛

  • MongoDB在內存充足的情況下數據都放入內存且有完整的索引支持,查詢效率較高

  • MongoDB的分片機制,支持海量數據的存儲和擴展

缺點:

  • 不支持事務

  • 不支持join、複雜查詢

初步調研下來,MongoDB具備我們需要的特性,而缺點不影響應用場景,故接下來我們就開始做實際的性能壓測。

二、壓測性能對比

1、準備條件

(1)MySQL 、MongoDB數據庫所在服務器硬件環境

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-1 服務器硬件環境主要參數

(2)最新的數據庫版本

MongoDB server version: 3.4.5

MongoDB client version: mongo-java-driver-2.14.3

MySQL server version:5.6.34

MySQL connector version: MySQL-connector-java-6.0.6

MongoDB使用的儲存引擎wiredTiger

MySQL使用的儲存引擎InnoDB

(3)數據庫表結構及索引

MongoDB索引為dateTime 且是唯一索引。我們實際測試使用的MongoDB數據結構及字段如圖2-1所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-1 MongoDB數據表記錄示例

MySQL索引為DATETIME,PARTNER_ID,GOODS_ID,SCOPE且是唯一索引。我們實際測試使用的MySQL數據結構及字段如圖2-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-2 MySQL數據表記錄示例

SQL語句根據datetime字段進行時間範圍的查詢

(4)連接池最大連接數都設置為200個,SQL語句調到最優

2、百萬、千萬級別的下不同查詢量不同併發量的壓測結果

數據庫表中記錄數總量在百萬、千萬級別的壓測數據及結果如表2-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-2 百萬、千萬級別的壓測數據及結果

3、億級別的下不同查詢量不同併發量的壓測結果

數據庫表中記錄數總量在億級別的壓測數據及結果如表2-3所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-3 億級別的壓測數據及結果

壓測結果分析:

  • 當每次查詢數據量在500條時,無論表中數據總量千萬或者億級別,MySQL和MongoDB在100線程併發的情況下查詢性能相當,表現良好,平均響應時間在500ms以內,TPS在230左右。

  • 當每次查詢數據量在5000條時,表中數據總量為千萬級別時,MongoDB在50線程併發情況下查詢性能不及MySQL 的一半,100線程併發情況查詢性能都很差,平均響應時間在4500ms左右,表中數據總量為億級別時,在50個及以上的併發情況下,MongoDB和MySQL性能都較差。

在本案例簡單數據模型下時間範圍內的等值查詢應用場景下,MongoDB在高併發條件下的大數據量查詢性能並沒有比MySQL更好。另外還有一點需要注意的是,在本案例中,數據總量由百萬級別到千萬級別再到億級別的變化過程中,對於查詢性能的影響都不是很大,但對於查詢數據量的數倍增長卻十分敏感,所以在考量數據庫查詢性能時,也要重點考量應用的單次查詢量的需求。

儘管MongoDB在我們的這種應用場景下並沒有達到預期的性能,我們也簡單地的調研了下MySQL和MongoDB對於內存的使用機制以及一些可能影響查詢效率的內部配置。

三、MySQL和MongoDB內存結構

1、InnoDB內存使用機制

InnoDB體系結構如圖3-1所示。

行情繫統提供的接口通過Redis獲取數據,目前使用Redis最多隻存儲了大概8000條左右的分鐘k的行情數據,考慮到將來可能會有更大數據量的查詢需求,需要查詢幾月甚至幾年的行情數據,要求數據庫在提供功能的同時又能保證性能和穩定性。Redis通常只用做較小數據量的內存數據庫,而傳統關係數據庫又有一定的查詢性能瓶頸,所以考慮調研一下其它的NoSQL數據庫。

一、為什麼調研MongoDB?

圖1-1是DB-Engines2017年11月數據庫的排名統計,可以看到MongoDB總排名在第5,在NoSQL數據庫中排名第1。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖1-1 DB-Engines2017年11月數據庫的排名統計

優點:

  • 社區活躍,用戶較多,應用廣泛

  • MongoDB在內存充足的情況下數據都放入內存且有完整的索引支持,查詢效率較高

  • MongoDB的分片機制,支持海量數據的存儲和擴展

缺點:

  • 不支持事務

  • 不支持join、複雜查詢

初步調研下來,MongoDB具備我們需要的特性,而缺點不影響應用場景,故接下來我們就開始做實際的性能壓測。

二、壓測性能對比

1、準備條件

(1)MySQL 、MongoDB數據庫所在服務器硬件環境

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-1 服務器硬件環境主要參數

(2)最新的數據庫版本

MongoDB server version: 3.4.5

MongoDB client version: mongo-java-driver-2.14.3

MySQL server version:5.6.34

MySQL connector version: MySQL-connector-java-6.0.6

MongoDB使用的儲存引擎wiredTiger

MySQL使用的儲存引擎InnoDB

(3)數據庫表結構及索引

MongoDB索引為dateTime 且是唯一索引。我們實際測試使用的MongoDB數據結構及字段如圖2-1所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-1 MongoDB數據表記錄示例

MySQL索引為DATETIME,PARTNER_ID,GOODS_ID,SCOPE且是唯一索引。我們實際測試使用的MySQL數據結構及字段如圖2-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-2 MySQL數據表記錄示例

SQL語句根據datetime字段進行時間範圍的查詢

(4)連接池最大連接數都設置為200個,SQL語句調到最優

2、百萬、千萬級別的下不同查詢量不同併發量的壓測結果

數據庫表中記錄數總量在百萬、千萬級別的壓測數據及結果如表2-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-2 百萬、千萬級別的壓測數據及結果

3、億級別的下不同查詢量不同併發量的壓測結果

數據庫表中記錄數總量在億級別的壓測數據及結果如表2-3所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-3 億級別的壓測數據及結果

壓測結果分析:

  • 當每次查詢數據量在500條時,無論表中數據總量千萬或者億級別,MySQL和MongoDB在100線程併發的情況下查詢性能相當,表現良好,平均響應時間在500ms以內,TPS在230左右。

  • 當每次查詢數據量在5000條時,表中數據總量為千萬級別時,MongoDB在50線程併發情況下查詢性能不及MySQL 的一半,100線程併發情況查詢性能都很差,平均響應時間在4500ms左右,表中數據總量為億級別時,在50個及以上的併發情況下,MongoDB和MySQL性能都較差。

在本案例簡單數據模型下時間範圍內的等值查詢應用場景下,MongoDB在高併發條件下的大數據量查詢性能並沒有比MySQL更好。另外還有一點需要注意的是,在本案例中,數據總量由百萬級別到千萬級別再到億級別的變化過程中,對於查詢性能的影響都不是很大,但對於查詢數據量的數倍增長卻十分敏感,所以在考量數據庫查詢性能時,也要重點考量應用的單次查詢量的需求。

儘管MongoDB在我們的這種應用場景下並沒有達到預期的性能,我們也簡單地的調研了下MySQL和MongoDB對於內存的使用機制以及一些可能影響查詢效率的內部配置。

三、MySQL和MongoDB內存結構

1、InnoDB內存使用機制

InnoDB體系結構如圖3-1所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖3-1 InnoDB體系結構

壓測MySQL使用的是InnoDB存儲引擎,InnoDB關於查詢效率有影響的兩個比較重要的參數分別是innodb_buffer_pool_size,innodb_read_ahead_threshold。

innodb_buffer_pool_size指的是InnoDB緩衝池的大小,本例中InnoDB緩衝池大小為20G,該參數的大小可通過命令指定innodb_buffer_pool_size 20G。緩衝池使用改進的LRU算法進行管理,維護一個LRU列表、一個FREE列表,FREE列表存放空閒頁,數據庫啟動時LRU列表是空的,當需要從緩衝池分頁時,首先從FREE列表查找空閒頁,有則放入LRU列表,否則LRU執行淘汰,淘汰尾部的頁分配給新頁。

innodb_read_ahead_threshold相對應的是數據預加載機制,innodb_read_ahead_threshold 30表示的是如果一個extent中的被順序讀取的page超過或者等於該參數變量的,InnoDB將會異步的將下一個extent讀取到buffer pool中,比如該參數的值為30,那麼當該extent中有30個pages被sequentially的讀取,則會觸發InnoDB linear預讀,將下一個extent讀到內存中;在沒有該變量之前,當訪問到extent的最後一個page的時候,InnoDB會決定是否將下一個extent放入到buffer pool中;可以在MySQL服務端通過show InnoDB status中的Pages read ahead和evicted without access兩個值來觀察預讀的情況:

  • Innodb_buffer_pool_read_ahead:表示通過預讀請求到buffer pool的pages;

  • Innodb_buffer_pool_read_ahead_evicted:表示由於請求到buffer pool中沒有被訪問,而驅逐出內存的頁數。

可以看出來,MySQL的緩衝池機制是能充分利用內存且有預加載機制,在某些條件下目標數據完全在內存中,也能夠具備非常好的查詢性能。

2、MongoDB的存儲結構及數據模型

(1)本例中MongoDB使用的儲存引擎是WiredTiger,WiredTiger的結構如圖3-2所示。

行情繫統提供的接口通過Redis獲取數據,目前使用Redis最多隻存儲了大概8000條左右的分鐘k的行情數據,考慮到將來可能會有更大數據量的查詢需求,需要查詢幾月甚至幾年的行情數據,要求數據庫在提供功能的同時又能保證性能和穩定性。Redis通常只用做較小數據量的內存數據庫,而傳統關係數據庫又有一定的查詢性能瓶頸,所以考慮調研一下其它的NoSQL數據庫。

一、為什麼調研MongoDB?

圖1-1是DB-Engines2017年11月數據庫的排名統計,可以看到MongoDB總排名在第5,在NoSQL數據庫中排名第1。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖1-1 DB-Engines2017年11月數據庫的排名統計

優點:

  • 社區活躍,用戶較多,應用廣泛

  • MongoDB在內存充足的情況下數據都放入內存且有完整的索引支持,查詢效率較高

  • MongoDB的分片機制,支持海量數據的存儲和擴展

缺點:

  • 不支持事務

  • 不支持join、複雜查詢

初步調研下來,MongoDB具備我們需要的特性,而缺點不影響應用場景,故接下來我們就開始做實際的性能壓測。

二、壓測性能對比

1、準備條件

(1)MySQL 、MongoDB數據庫所在服務器硬件環境

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-1 服務器硬件環境主要參數

(2)最新的數據庫版本

MongoDB server version: 3.4.5

MongoDB client version: mongo-java-driver-2.14.3

MySQL server version:5.6.34

MySQL connector version: MySQL-connector-java-6.0.6

MongoDB使用的儲存引擎wiredTiger

MySQL使用的儲存引擎InnoDB

(3)數據庫表結構及索引

MongoDB索引為dateTime 且是唯一索引。我們實際測試使用的MongoDB數據結構及字段如圖2-1所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-1 MongoDB數據表記錄示例

MySQL索引為DATETIME,PARTNER_ID,GOODS_ID,SCOPE且是唯一索引。我們實際測試使用的MySQL數據結構及字段如圖2-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-2 MySQL數據表記錄示例

SQL語句根據datetime字段進行時間範圍的查詢

(4)連接池最大連接數都設置為200個,SQL語句調到最優

2、百萬、千萬級別的下不同查詢量不同併發量的壓測結果

數據庫表中記錄數總量在百萬、千萬級別的壓測數據及結果如表2-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-2 百萬、千萬級別的壓測數據及結果

3、億級別的下不同查詢量不同併發量的壓測結果

數據庫表中記錄數總量在億級別的壓測數據及結果如表2-3所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-3 億級別的壓測數據及結果

壓測結果分析:

  • 當每次查詢數據量在500條時,無論表中數據總量千萬或者億級別,MySQL和MongoDB在100線程併發的情況下查詢性能相當,表現良好,平均響應時間在500ms以內,TPS在230左右。

  • 當每次查詢數據量在5000條時,表中數據總量為千萬級別時,MongoDB在50線程併發情況下查詢性能不及MySQL 的一半,100線程併發情況查詢性能都很差,平均響應時間在4500ms左右,表中數據總量為億級別時,在50個及以上的併發情況下,MongoDB和MySQL性能都較差。

在本案例簡單數據模型下時間範圍內的等值查詢應用場景下,MongoDB在高併發條件下的大數據量查詢性能並沒有比MySQL更好。另外還有一點需要注意的是,在本案例中,數據總量由百萬級別到千萬級別再到億級別的變化過程中,對於查詢性能的影響都不是很大,但對於查詢數據量的數倍增長卻十分敏感,所以在考量數據庫查詢性能時,也要重點考量應用的單次查詢量的需求。

儘管MongoDB在我們的這種應用場景下並沒有達到預期的性能,我們也簡單地的調研了下MySQL和MongoDB對於內存的使用機制以及一些可能影響查詢效率的內部配置。

三、MySQL和MongoDB內存結構

1、InnoDB內存使用機制

InnoDB體系結構如圖3-1所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖3-1 InnoDB體系結構

壓測MySQL使用的是InnoDB存儲引擎,InnoDB關於查詢效率有影響的兩個比較重要的參數分別是innodb_buffer_pool_size,innodb_read_ahead_threshold。

innodb_buffer_pool_size指的是InnoDB緩衝池的大小,本例中InnoDB緩衝池大小為20G,該參數的大小可通過命令指定innodb_buffer_pool_size 20G。緩衝池使用改進的LRU算法進行管理,維護一個LRU列表、一個FREE列表,FREE列表存放空閒頁,數據庫啟動時LRU列表是空的,當需要從緩衝池分頁時,首先從FREE列表查找空閒頁,有則放入LRU列表,否則LRU執行淘汰,淘汰尾部的頁分配給新頁。

innodb_read_ahead_threshold相對應的是數據預加載機制,innodb_read_ahead_threshold 30表示的是如果一個extent中的被順序讀取的page超過或者等於該參數變量的,InnoDB將會異步的將下一個extent讀取到buffer pool中,比如該參數的值為30,那麼當該extent中有30個pages被sequentially的讀取,則會觸發InnoDB linear預讀,將下一個extent讀到內存中;在沒有該變量之前,當訪問到extent的最後一個page的時候,InnoDB會決定是否將下一個extent放入到buffer pool中;可以在MySQL服務端通過show InnoDB status中的Pages read ahead和evicted without access兩個值來觀察預讀的情況:

  • Innodb_buffer_pool_read_ahead:表示通過預讀請求到buffer pool的pages;

  • Innodb_buffer_pool_read_ahead_evicted:表示由於請求到buffer pool中沒有被訪問,而驅逐出內存的頁數。

可以看出來,MySQL的緩衝池機制是能充分利用內存且有預加載機制,在某些條件下目標數據完全在內存中,也能夠具備非常好的查詢性能。

2、MongoDB的存儲結構及數據模型

(1)本例中MongoDB使用的儲存引擎是WiredTiger,WiredTiger的結構如圖3-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖3-2 WiredTiger Engine的結構

WiredTiger Cache的實現原理圖如圖3-3所示。

行情繫統提供的接口通過Redis獲取數據,目前使用Redis最多隻存儲了大概8000條左右的分鐘k的行情數據,考慮到將來可能會有更大數據量的查詢需求,需要查詢幾月甚至幾年的行情數據,要求數據庫在提供功能的同時又能保證性能和穩定性。Redis通常只用做較小數據量的內存數據庫,而傳統關係數據庫又有一定的查詢性能瓶頸,所以考慮調研一下其它的NoSQL數據庫。

一、為什麼調研MongoDB?

圖1-1是DB-Engines2017年11月數據庫的排名統計,可以看到MongoDB總排名在第5,在NoSQL數據庫中排名第1。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖1-1 DB-Engines2017年11月數據庫的排名統計

優點:

  • 社區活躍,用戶較多,應用廣泛

  • MongoDB在內存充足的情況下數據都放入內存且有完整的索引支持,查詢效率較高

  • MongoDB的分片機制,支持海量數據的存儲和擴展

缺點:

  • 不支持事務

  • 不支持join、複雜查詢

初步調研下來,MongoDB具備我們需要的特性,而缺點不影響應用場景,故接下來我們就開始做實際的性能壓測。

二、壓測性能對比

1、準備條件

(1)MySQL 、MongoDB數據庫所在服務器硬件環境

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-1 服務器硬件環境主要參數

(2)最新的數據庫版本

MongoDB server version: 3.4.5

MongoDB client version: mongo-java-driver-2.14.3

MySQL server version:5.6.34

MySQL connector version: MySQL-connector-java-6.0.6

MongoDB使用的儲存引擎wiredTiger

MySQL使用的儲存引擎InnoDB

(3)數據庫表結構及索引

MongoDB索引為dateTime 且是唯一索引。我們實際測試使用的MongoDB數據結構及字段如圖2-1所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-1 MongoDB數據表記錄示例

MySQL索引為DATETIME,PARTNER_ID,GOODS_ID,SCOPE且是唯一索引。我們實際測試使用的MySQL數據結構及字段如圖2-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-2 MySQL數據表記錄示例

SQL語句根據datetime字段進行時間範圍的查詢

(4)連接池最大連接數都設置為200個,SQL語句調到最優

2、百萬、千萬級別的下不同查詢量不同併發量的壓測結果

數據庫表中記錄數總量在百萬、千萬級別的壓測數據及結果如表2-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-2 百萬、千萬級別的壓測數據及結果

3、億級別的下不同查詢量不同併發量的壓測結果

數據庫表中記錄數總量在億級別的壓測數據及結果如表2-3所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-3 億級別的壓測數據及結果

壓測結果分析:

  • 當每次查詢數據量在500條時,無論表中數據總量千萬或者億級別,MySQL和MongoDB在100線程併發的情況下查詢性能相當,表現良好,平均響應時間在500ms以內,TPS在230左右。

  • 當每次查詢數據量在5000條時,表中數據總量為千萬級別時,MongoDB在50線程併發情況下查詢性能不及MySQL 的一半,100線程併發情況查詢性能都很差,平均響應時間在4500ms左右,表中數據總量為億級別時,在50個及以上的併發情況下,MongoDB和MySQL性能都較差。

在本案例簡單數據模型下時間範圍內的等值查詢應用場景下,MongoDB在高併發條件下的大數據量查詢性能並沒有比MySQL更好。另外還有一點需要注意的是,在本案例中,數據總量由百萬級別到千萬級別再到億級別的變化過程中,對於查詢性能的影響都不是很大,但對於查詢數據量的數倍增長卻十分敏感,所以在考量數據庫查詢性能時,也要重點考量應用的單次查詢量的需求。

儘管MongoDB在我們的這種應用場景下並沒有達到預期的性能,我們也簡單地的調研了下MySQL和MongoDB對於內存的使用機制以及一些可能影響查詢效率的內部配置。

三、MySQL和MongoDB內存結構

1、InnoDB內存使用機制

InnoDB體系結構如圖3-1所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖3-1 InnoDB體系結構

壓測MySQL使用的是InnoDB存儲引擎,InnoDB關於查詢效率有影響的兩個比較重要的參數分別是innodb_buffer_pool_size,innodb_read_ahead_threshold。

innodb_buffer_pool_size指的是InnoDB緩衝池的大小,本例中InnoDB緩衝池大小為20G,該參數的大小可通過命令指定innodb_buffer_pool_size 20G。緩衝池使用改進的LRU算法進行管理,維護一個LRU列表、一個FREE列表,FREE列表存放空閒頁,數據庫啟動時LRU列表是空的,當需要從緩衝池分頁時,首先從FREE列表查找空閒頁,有則放入LRU列表,否則LRU執行淘汰,淘汰尾部的頁分配給新頁。

innodb_read_ahead_threshold相對應的是數據預加載機制,innodb_read_ahead_threshold 30表示的是如果一個extent中的被順序讀取的page超過或者等於該參數變量的,InnoDB將會異步的將下一個extent讀取到buffer pool中,比如該參數的值為30,那麼當該extent中有30個pages被sequentially的讀取,則會觸發InnoDB linear預讀,將下一個extent讀到內存中;在沒有該變量之前,當訪問到extent的最後一個page的時候,InnoDB會決定是否將下一個extent放入到buffer pool中;可以在MySQL服務端通過show InnoDB status中的Pages read ahead和evicted without access兩個值來觀察預讀的情況:

  • Innodb_buffer_pool_read_ahead:表示通過預讀請求到buffer pool的pages;

  • Innodb_buffer_pool_read_ahead_evicted:表示由於請求到buffer pool中沒有被訪問,而驅逐出內存的頁數。

可以看出來,MySQL的緩衝池機制是能充分利用內存且有預加載機制,在某些條件下目標數據完全在內存中,也能夠具備非常好的查詢性能。

2、MongoDB的存儲結構及數據模型

(1)本例中MongoDB使用的儲存引擎是WiredTiger,WiredTiger的結構如圖3-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖3-2 WiredTiger Engine的結構

WiredTiger Cache的實現原理圖如圖3-3所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖3-3 WiredTiger Cache的實現原理圖

Wiredtiger的Cache採用Btree的方式組織,每個Btree節點為一個page,root page是btree的根節點,internal page是btree的中間索引節點,leaf page是真正存儲數據的葉子節點;btree的數據以page為單位按需從磁盤加載或寫入磁盤。

可以通過在配置文件中指定storage.wiredTiger.engineConfig.cacheSizeGB參數設定引擎使用的內存量。此內存用於緩存工作集數據(索引、namespace,未提交的write,query緩衝等)。

(2)數據模型

內嵌

MongoDB的文檔是無模式的,所以可以支持各種數據結構,內嵌模型也叫做非規格化模型(denormalized)。在MongoDB中,一組相關的數據可以是一個文檔,也可以是組成文檔的一部分。

行情繫統提供的接口通過Redis獲取數據,目前使用Redis最多隻存儲了大概8000條左右的分鐘k的行情數據,考慮到將來可能會有更大數據量的查詢需求,需要查詢幾月甚至幾年的行情數據,要求數據庫在提供功能的同時又能保證性能和穩定性。Redis通常只用做較小數據量的內存數據庫,而傳統關係數據庫又有一定的查詢性能瓶頸,所以考慮調研一下其它的NoSQL數據庫。

一、為什麼調研MongoDB?

圖1-1是DB-Engines2017年11月數據庫的排名統計,可以看到MongoDB總排名在第5,在NoSQL數據庫中排名第1。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖1-1 DB-Engines2017年11月數據庫的排名統計

優點:

  • 社區活躍,用戶較多,應用廣泛

  • MongoDB在內存充足的情況下數據都放入內存且有完整的索引支持,查詢效率較高

  • MongoDB的分片機制,支持海量數據的存儲和擴展

缺點:

  • 不支持事務

  • 不支持join、複雜查詢

初步調研下來,MongoDB具備我們需要的特性,而缺點不影響應用場景,故接下來我們就開始做實際的性能壓測。

二、壓測性能對比

1、準備條件

(1)MySQL 、MongoDB數據庫所在服務器硬件環境

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-1 服務器硬件環境主要參數

(2)最新的數據庫版本

MongoDB server version: 3.4.5

MongoDB client version: mongo-java-driver-2.14.3

MySQL server version:5.6.34

MySQL connector version: MySQL-connector-java-6.0.6

MongoDB使用的儲存引擎wiredTiger

MySQL使用的儲存引擎InnoDB

(3)數據庫表結構及索引

MongoDB索引為dateTime 且是唯一索引。我們實際測試使用的MongoDB數據結構及字段如圖2-1所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-1 MongoDB數據表記錄示例

MySQL索引為DATETIME,PARTNER_ID,GOODS_ID,SCOPE且是唯一索引。我們實際測試使用的MySQL數據結構及字段如圖2-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-2 MySQL數據表記錄示例

SQL語句根據datetime字段進行時間範圍的查詢

(4)連接池最大連接數都設置為200個,SQL語句調到最優

2、百萬、千萬級別的下不同查詢量不同併發量的壓測結果

數據庫表中記錄數總量在百萬、千萬級別的壓測數據及結果如表2-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-2 百萬、千萬級別的壓測數據及結果

3、億級別的下不同查詢量不同併發量的壓測結果

數據庫表中記錄數總量在億級別的壓測數據及結果如表2-3所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-3 億級別的壓測數據及結果

壓測結果分析:

  • 當每次查詢數據量在500條時,無論表中數據總量千萬或者億級別,MySQL和MongoDB在100線程併發的情況下查詢性能相當,表現良好,平均響應時間在500ms以內,TPS在230左右。

  • 當每次查詢數據量在5000條時,表中數據總量為千萬級別時,MongoDB在50線程併發情況下查詢性能不及MySQL 的一半,100線程併發情況查詢性能都很差,平均響應時間在4500ms左右,表中數據總量為億級別時,在50個及以上的併發情況下,MongoDB和MySQL性能都較差。

在本案例簡單數據模型下時間範圍內的等值查詢應用場景下,MongoDB在高併發條件下的大數據量查詢性能並沒有比MySQL更好。另外還有一點需要注意的是,在本案例中,數據總量由百萬級別到千萬級別再到億級別的變化過程中,對於查詢性能的影響都不是很大,但對於查詢數據量的數倍增長卻十分敏感,所以在考量數據庫查詢性能時,也要重點考量應用的單次查詢量的需求。

儘管MongoDB在我們的這種應用場景下並沒有達到預期的性能,我們也簡單地的調研了下MySQL和MongoDB對於內存的使用機制以及一些可能影響查詢效率的內部配置。

三、MySQL和MongoDB內存結構

1、InnoDB內存使用機制

InnoDB體系結構如圖3-1所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖3-1 InnoDB體系結構

壓測MySQL使用的是InnoDB存儲引擎,InnoDB關於查詢效率有影響的兩個比較重要的參數分別是innodb_buffer_pool_size,innodb_read_ahead_threshold。

innodb_buffer_pool_size指的是InnoDB緩衝池的大小,本例中InnoDB緩衝池大小為20G,該參數的大小可通過命令指定innodb_buffer_pool_size 20G。緩衝池使用改進的LRU算法進行管理,維護一個LRU列表、一個FREE列表,FREE列表存放空閒頁,數據庫啟動時LRU列表是空的,當需要從緩衝池分頁時,首先從FREE列表查找空閒頁,有則放入LRU列表,否則LRU執行淘汰,淘汰尾部的頁分配給新頁。

innodb_read_ahead_threshold相對應的是數據預加載機制,innodb_read_ahead_threshold 30表示的是如果一個extent中的被順序讀取的page超過或者等於該參數變量的,InnoDB將會異步的將下一個extent讀取到buffer pool中,比如該參數的值為30,那麼當該extent中有30個pages被sequentially的讀取,則會觸發InnoDB linear預讀,將下一個extent讀到內存中;在沒有該變量之前,當訪問到extent的最後一個page的時候,InnoDB會決定是否將下一個extent放入到buffer pool中;可以在MySQL服務端通過show InnoDB status中的Pages read ahead和evicted without access兩個值來觀察預讀的情況:

  • Innodb_buffer_pool_read_ahead:表示通過預讀請求到buffer pool的pages;

  • Innodb_buffer_pool_read_ahead_evicted:表示由於請求到buffer pool中沒有被訪問,而驅逐出內存的頁數。

可以看出來,MySQL的緩衝池機制是能充分利用內存且有預加載機制,在某些條件下目標數據完全在內存中,也能夠具備非常好的查詢性能。

2、MongoDB的存儲結構及數據模型

(1)本例中MongoDB使用的儲存引擎是WiredTiger,WiredTiger的結構如圖3-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖3-2 WiredTiger Engine的結構

WiredTiger Cache的實現原理圖如圖3-3所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖3-3 WiredTiger Cache的實現原理圖

Wiredtiger的Cache採用Btree的方式組織,每個Btree節點為一個page,root page是btree的根節點,internal page是btree的中間索引節點,leaf page是真正存儲數據的葉子節點;btree的數據以page為單位按需從磁盤加載或寫入磁盤。

可以通過在配置文件中指定storage.wiredTiger.engineConfig.cacheSizeGB參數設定引擎使用的內存量。此內存用於緩存工作集數據(索引、namespace,未提交的write,query緩衝等)。

(2)數據模型

內嵌

MongoDB的文檔是無模式的,所以可以支持各種數據結構,內嵌模型也叫做非規格化模型(denormalized)。在MongoDB中,一組相關的數據可以是一個文檔,也可以是組成文檔的一部分。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖3-4 內嵌文檔示例

內嵌類型支持一組相關的數據存儲在一個文檔中,這樣的好處就是,應用程序可以通過比較少的的查詢和更新操作來完成一些常規的數據的查詢和更新工作。

當遇到以下情況的時候,我們應該考慮使用內嵌類型:

如果數據關係是一種一對一的包含關係,例如下面的文檔,每個人都有一個contact字段來描述這個人的聯繫方式。像這種一對一的關係,使用內嵌類型可以很方便的進行數據的查詢和更新。

{

  ”_id”: ,

  ”name”: “Wilber”,

  ”contact”: {

     “phone”: “12345678”,

     “email”: “[email protected]

   }

}

如果數據的關係是一對多,那麼也可以考慮使用內嵌模型。例如下面的文檔,用posts字段記錄所有用戶發佈的博客。在這中情況中,如果應用程序會經常通過用戶名字段來查詢改用戶發佈的博客信息。那麼,把posts作為內嵌字段會是一個比較好的選擇,這樣就可以減少很多查詢的操作。

{

   “_id”: ,

   “name”: “Wilber”,

   “contact”: {

    ”phone”: “12345678”,

    ”email”: “[email protected]

  },

  ”posts”: [

  {

    ”title”: “Indexes in MongoDB”,

    ”created”: “12/01/2014”,

    ”link”: “www.linuxidc.com”

  },

  {

    ”title”: “Replication in MongoDB”,

    ”created”: “12/02/2014”,

    ”link”: “www.linuxidc.com”

  },

  {

    ”title”: “Sharding in MongoDB”,

    ”created”: “12/03/2014”,

    ”link”: “www.linuxidc.com”

  }

 ]

}

根據上面的描述可以看出,內嵌模型可以給應用程序提供很好的數據查詢性能,因為基於內嵌模型,可以通過一次數據庫操作得到所有相關的數據。同時,內嵌模型可以使數據更新操作變成一個原子寫操作。然而,內嵌模型也可能引入一些問題,比如說文檔會越來越大,這樣就可能會影響數據庫寫操作的性能,還可能會產生數據碎片(data fragmentation)。

引用

相對於嵌入模型,引用模型又稱規格化模型(Normalized data models),通過引用的方式來表示數據之間的關係。這裡同樣使用來自MongoDB文檔中的圖片,在這個模型中,把contact和access從user中移出,並通過user_id作為索引來表示它們之間的聯繫。

行情繫統提供的接口通過Redis獲取數據,目前使用Redis最多隻存儲了大概8000條左右的分鐘k的行情數據,考慮到將來可能會有更大數據量的查詢需求,需要查詢幾月甚至幾年的行情數據,要求數據庫在提供功能的同時又能保證性能和穩定性。Redis通常只用做較小數據量的內存數據庫,而傳統關係數據庫又有一定的查詢性能瓶頸,所以考慮調研一下其它的NoSQL數據庫。

一、為什麼調研MongoDB?

圖1-1是DB-Engines2017年11月數據庫的排名統計,可以看到MongoDB總排名在第5,在NoSQL數據庫中排名第1。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖1-1 DB-Engines2017年11月數據庫的排名統計

優點:

  • 社區活躍,用戶較多,應用廣泛

  • MongoDB在內存充足的情況下數據都放入內存且有完整的索引支持,查詢效率較高

  • MongoDB的分片機制,支持海量數據的存儲和擴展

缺點:

  • 不支持事務

  • 不支持join、複雜查詢

初步調研下來,MongoDB具備我們需要的特性,而缺點不影響應用場景,故接下來我們就開始做實際的性能壓測。

二、壓測性能對比

1、準備條件

(1)MySQL 、MongoDB數據庫所在服務器硬件環境

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-1 服務器硬件環境主要參數

(2)最新的數據庫版本

MongoDB server version: 3.4.5

MongoDB client version: mongo-java-driver-2.14.3

MySQL server version:5.6.34

MySQL connector version: MySQL-connector-java-6.0.6

MongoDB使用的儲存引擎wiredTiger

MySQL使用的儲存引擎InnoDB

(3)數據庫表結構及索引

MongoDB索引為dateTime 且是唯一索引。我們實際測試使用的MongoDB數據結構及字段如圖2-1所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-1 MongoDB數據表記錄示例

MySQL索引為DATETIME,PARTNER_ID,GOODS_ID,SCOPE且是唯一索引。我們實際測試使用的MySQL數據結構及字段如圖2-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖2-2 MySQL數據表記錄示例

SQL語句根據datetime字段進行時間範圍的查詢

(4)連接池最大連接數都設置為200個,SQL語句調到最優

2、百萬、千萬級別的下不同查詢量不同併發量的壓測結果

數據庫表中記錄數總量在百萬、千萬級別的壓測數據及結果如表2-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-2 百萬、千萬級別的壓測數據及結果

3、億級別的下不同查詢量不同併發量的壓測結果

數據庫表中記錄數總量在億級別的壓測數據及結果如表2-3所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

表2-3 億級別的壓測數據及結果

壓測結果分析:

  • 當每次查詢數據量在500條時,無論表中數據總量千萬或者億級別,MySQL和MongoDB在100線程併發的情況下查詢性能相當,表現良好,平均響應時間在500ms以內,TPS在230左右。

  • 當每次查詢數據量在5000條時,表中數據總量為千萬級別時,MongoDB在50線程併發情況下查詢性能不及MySQL 的一半,100線程併發情況查詢性能都很差,平均響應時間在4500ms左右,表中數據總量為億級別時,在50個及以上的併發情況下,MongoDB和MySQL性能都較差。

在本案例簡單數據模型下時間範圍內的等值查詢應用場景下,MongoDB在高併發條件下的大數據量查詢性能並沒有比MySQL更好。另外還有一點需要注意的是,在本案例中,數據總量由百萬級別到千萬級別再到億級別的變化過程中,對於查詢性能的影響都不是很大,但對於查詢數據量的數倍增長卻十分敏感,所以在考量數據庫查詢性能時,也要重點考量應用的單次查詢量的需求。

儘管MongoDB在我們的這種應用場景下並沒有達到預期的性能,我們也簡單地的調研了下MySQL和MongoDB對於內存的使用機制以及一些可能影響查詢效率的內部配置。

三、MySQL和MongoDB內存結構

1、InnoDB內存使用機制

InnoDB體系結構如圖3-1所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖3-1 InnoDB體系結構

壓測MySQL使用的是InnoDB存儲引擎,InnoDB關於查詢效率有影響的兩個比較重要的參數分別是innodb_buffer_pool_size,innodb_read_ahead_threshold。

innodb_buffer_pool_size指的是InnoDB緩衝池的大小,本例中InnoDB緩衝池大小為20G,該參數的大小可通過命令指定innodb_buffer_pool_size 20G。緩衝池使用改進的LRU算法進行管理,維護一個LRU列表、一個FREE列表,FREE列表存放空閒頁,數據庫啟動時LRU列表是空的,當需要從緩衝池分頁時,首先從FREE列表查找空閒頁,有則放入LRU列表,否則LRU執行淘汰,淘汰尾部的頁分配給新頁。

innodb_read_ahead_threshold相對應的是數據預加載機制,innodb_read_ahead_threshold 30表示的是如果一個extent中的被順序讀取的page超過或者等於該參數變量的,InnoDB將會異步的將下一個extent讀取到buffer pool中,比如該參數的值為30,那麼當該extent中有30個pages被sequentially的讀取,則會觸發InnoDB linear預讀,將下一個extent讀到內存中;在沒有該變量之前,當訪問到extent的最後一個page的時候,InnoDB會決定是否將下一個extent放入到buffer pool中;可以在MySQL服務端通過show InnoDB status中的Pages read ahead和evicted without access兩個值來觀察預讀的情況:

  • Innodb_buffer_pool_read_ahead:表示通過預讀請求到buffer pool的pages;

  • Innodb_buffer_pool_read_ahead_evicted:表示由於請求到buffer pool中沒有被訪問,而驅逐出內存的頁數。

可以看出來,MySQL的緩衝池機制是能充分利用內存且有預加載機制,在某些條件下目標數據完全在內存中,也能夠具備非常好的查詢性能。

2、MongoDB的存儲結構及數據模型

(1)本例中MongoDB使用的儲存引擎是WiredTiger,WiredTiger的結構如圖3-2所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖3-2 WiredTiger Engine的結構

WiredTiger Cache的實現原理圖如圖3-3所示。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖3-3 WiredTiger Cache的實現原理圖

Wiredtiger的Cache採用Btree的方式組織,每個Btree節點為一個page,root page是btree的根節點,internal page是btree的中間索引節點,leaf page是真正存儲數據的葉子節點;btree的數據以page為單位按需從磁盤加載或寫入磁盤。

可以通過在配置文件中指定storage.wiredTiger.engineConfig.cacheSizeGB參數設定引擎使用的內存量。此內存用於緩存工作集數據(索引、namespace,未提交的write,query緩衝等)。

(2)數據模型

內嵌

MongoDB的文檔是無模式的,所以可以支持各種數據結構,內嵌模型也叫做非規格化模型(denormalized)。在MongoDB中,一組相關的數據可以是一個文檔,也可以是組成文檔的一部分。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖3-4 內嵌文檔示例

內嵌類型支持一組相關的數據存儲在一個文檔中,這樣的好處就是,應用程序可以通過比較少的的查詢和更新操作來完成一些常規的數據的查詢和更新工作。

當遇到以下情況的時候,我們應該考慮使用內嵌類型:

如果數據關係是一種一對一的包含關係,例如下面的文檔,每個人都有一個contact字段來描述這個人的聯繫方式。像這種一對一的關係,使用內嵌類型可以很方便的進行數據的查詢和更新。

{

  ”_id”: ,

  ”name”: “Wilber”,

  ”contact”: {

     “phone”: “12345678”,

     “email”: “[email protected]

   }

}

如果數據的關係是一對多,那麼也可以考慮使用內嵌模型。例如下面的文檔,用posts字段記錄所有用戶發佈的博客。在這中情況中,如果應用程序會經常通過用戶名字段來查詢改用戶發佈的博客信息。那麼,把posts作為內嵌字段會是一個比較好的選擇,這樣就可以減少很多查詢的操作。

{

   “_id”: ,

   “name”: “Wilber”,

   “contact”: {

    ”phone”: “12345678”,

    ”email”: “[email protected]

  },

  ”posts”: [

  {

    ”title”: “Indexes in MongoDB”,

    ”created”: “12/01/2014”,

    ”link”: “www.linuxidc.com”

  },

  {

    ”title”: “Replication in MongoDB”,

    ”created”: “12/02/2014”,

    ”link”: “www.linuxidc.com”

  },

  {

    ”title”: “Sharding in MongoDB”,

    ”created”: “12/03/2014”,

    ”link”: “www.linuxidc.com”

  }

 ]

}

根據上面的描述可以看出,內嵌模型可以給應用程序提供很好的數據查詢性能,因為基於內嵌模型,可以通過一次數據庫操作得到所有相關的數據。同時,內嵌模型可以使數據更新操作變成一個原子寫操作。然而,內嵌模型也可能引入一些問題,比如說文檔會越來越大,這樣就可能會影響數據庫寫操作的性能,還可能會產生數據碎片(data fragmentation)。

引用

相對於嵌入模型,引用模型又稱規格化模型(Normalized data models),通過引用的方式來表示數據之間的關係。這裡同樣使用來自MongoDB文檔中的圖片,在這個模型中,把contact和access從user中移出,並通過user_id作為索引來表示它們之間的聯繫。

從MySQL和MongoDB的對比,看SQL與NoSQL的較量

圖3-5 引用文檔示例

當我們遇到以下情況的時候,就可以考慮使用引用模型了:

  • 使用內嵌模型往往會帶來數據的冗餘,卻可以提升數據查詢的效率。但是,當應用程序基本上不通過內嵌模型查詢,或者說查詢效率的提升不足以彌補數據冗餘帶來的問題時,我們就應該考慮引用模型了。

  • 當需要實現複雜的多對多關係時,可以考慮引用模型。比如我們熟知的例子,學生-課程-老師關係,如果用引用模型來實現三者的關係,可能會比內嵌模型更清晰直觀,同時會減少很多冗餘數據。

  • 當需要實現複雜的樹形關係時,可以考慮引用模型。

四、應用場景分析

1、MongoDB的應用場景

(1)表結構不明確且數據不斷變大

MongoDB是非結構化文檔數據庫,擴展字段很容易且不會影響原有數據。內容管理或者博客平臺等,例如圈子系統、存儲用戶評論之類的。

(2)更高的寫入負載

MongoDB側重高數據寫入的性能,而非事務安全,適合業務系統中有大量“低價值”數據的場景。本身存的就是json格式數據。例如做日誌系統。

(3)數據量很大或者將來會變得很大

MySQL單表數據量達到5-10G時會出現明細的性能降級,需要做數據的水平和垂直拆分、庫的拆分完成擴展,MongoDB內建了sharding、很多數據分片的特性,容易水平擴展,比較好的適應大數據量增長的需求。

(4)高可用性

自帶高可用,自動主從切換(副本集)


不適用的場景

(1)MongoDB不支持事務操作,需要用到事務的應用建議不用MongoDB。

(2)MongoDB目前不支持join操作,需要複雜查詢的應用也不建議使用MongoDB。

2、關係型數據庫和非關係型數據庫的應用場景對比

關係型數據庫適合存儲結構化數據,如用戶的帳號、地址:

  • 這些數據通常需要做結構化查詢,比如join。這時候,關係型數據庫就要勝出一籌

  • 這些數據的規模、增長的速度通常是可以預期的

  • 事務性、一致性

NoSQL適合存儲非結構化數據,如文章、評論:

  • 這些數據通常用於模糊處理,如全文搜索、機器學習

  • 這些數據是海量的,而且增長的速度是難以預期的

  • 根據數據的特點,NoSQL數據庫通常具有無限(至少接近)伸縮性

  • 按key獲取數據效率很高,但是對join或其它結構化查詢的支持就比較差

相關推薦

推薦中...