不要再選擇MySQL了

banq發表於2016-11-07
考慮要選擇MySQL?還是選擇使用別的資料庫吧。已經在用MySQL?遷移。對於每一個建立在MySQL中的成功專案,你可以發現時間會浪費在彌補MySQL上的不足,毫無意義,其成就感根本無法抵消在MySQL上的努力付出。

資料庫是填補從單純的儲存到複雜和有趣的資料處理之間的角色;MySQL壞在希望兼顧這不同的極端任務。而真正的應用都是介於兩極之間,結果會遭遇MySQL這種定位帶來的不匹配痛苦:
1.MySQL在儲存方面不行
2.MySQL在資料處理儲存方面也是不行
3.MySQL的設計就不行

這篇文章是受到PHP: A Fractal of Bad Design.啟發,如果對MySQL粉有所冒犯,請原諒。

原文見:

The Codex » Do Not Pass This Way Again,大意如下:

儲存方面
儲存應該有四個屬性:
1.從應用程式中獲取資料並儲存他們。
2.保持資料的安全性,防止損失或意外變化。
3.嚮應用程式提供儲存的資料。
4.給管理員有效的管理工具

MySQL在儲存上存在下面問題:
1.隱式轉換(特別是來自於或從字串型別的轉換)可以修改MySQL的行為。許多隱式轉換保持沉默(沒有警告,沒有診斷),設計上更可能是讓開發人員完全沒有注意這些,直至令人驚訝的事情發生。

2.違反輸出型別基本約束(範圍、長度)的轉換經常強行挾持資料而不是失敗放棄。有時這會引發一個警告,你的應用程式檢查這些?這種行為是與許多型別的系統(像PHP和遠端像Perl)非常類似。

3.轉換行為取決於每一個連線配置值(sql_mode),有大量可能狀態,使其從手工測試到程式碼或從工具到工具之間遷移時難以實現預期一致性。

4.MySQL推薦使用UTF-8,但是預設是Latin-1,MySQL 5.5的utf8只有3個位元組BMP,雖然支援4個位元組utf-8,但是需要設定字符集卻是utf8mb4,這種特殊方式讓人困惑。
在MySQL這些編碼的實現細節,如UTF8 3位元組的限制,往往會洩露到客戶端應用程式。不適合MySQL理解的儲存編碼的資料將被轉化,預設或截斷或更換。

5.TIMESTAMP 型別透過儲存值在一個時區(UTC)中試圖做得更聰明,但它做得太少,很難說MySQL對你的資料幫助你做了正確的事。
foo <'2012-04-01 09:00:00'的結果還取決於你查詢時是什麼時候,除非你非常小心你的連線時區。DATETIME 的時間並不能和TIMESTAMP處理得到的時間相同。

儲存資料
對意外情況發生:像大多數磁碟備份儲存系統,MySQL是用磁碟和檔案系統的資料作為資料儲存體。MySQL的映象或硬體容錯方面並沒有如Oracle ASM提供額外的功能。然而,與許多其他系統共享存在限制。

使用InnoDB儲存引擎時(從MySQL 5.5設為預設),MySQL維護頁校驗以便來檢測潛在的儲存導致的中斷。然而,許多第三方的應用軟體,以及從可以使用MyISAM的早期MySQL版本升級的使用者,會在正常關機下經常損壞的資料檔案。

....

此外,一些明顯無害的功能可能會導致備份或副本與原始資料庫無法同步,可見在預設配置中的下面這些語句功能:
1.AUTO_INCREMENT 和 UPDATE .
2.AUTO_INCREMENT 和 INSERT (有時 驚奇)
3.觸發器Triggers.
4.User-defined (native) 原生函式
5.儲存過程SQL
6.DELETE ... LIMIT 和 UPDATE ... LIMIT語句,
7.INSERT ... ON DUPLICATE KEY UPDATE
8.LOAD DATA 批次載入資料

獲取資料
大部分符合預期正常工作。MySQL主要儲存儲存資料的時候做魔術,而不是獲取時。然而,在獲取返回資料之前,有一些東西是透過隱式變換儲存的:
下面展示查詢並不能和儲存預期的一致:

owen@scratch> CREATE TABLE account (
    ->     accountid INTEGER
    ->         AUTO_INCREMENT
    ->         PRIMARY KEY,
    ->     discountid INTEGER
    -> );
Query OK, 0 rows affected (0.54 sec)

owen@scratch> INSERT INTO account
    ->     (discountid)
    -> VALUES
    ->     (0),
    ->     (1),
    ->     (2);
Query OK, 3 rows affected (0.03 sec)
Records: 3  Duplicates: 0  Warnings: 0

owen@scratch> SELECT *
    -> FROM account
    -> WHERE discountid = 'banana';
+-----------+------------+
| accountid | discountid |
+-----------+------------+
|               1 |               0 |
+-----------+------------+
1 row in set, 1 warning (0.05 sec)
<p class="indent">

果然意外,那麼至少有一個警告吧:

owen@scratch> SHOW WARNINGS;
+---------+------+--------------------------------------------+
| Level      | Code | Message                                    |
+---------+------+--------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'banana' |
+---------+------+--------------------------------------------+
1 row in set (0.03 sec)
<p class="indent">


由於原文篇幅較長,可以說列數太多MySQL問題,可謂是MySQL問題大全:

https://grimoire.ca/mysql/choose-something-else


[該貼被banq於2016-11-07 18:32修改過]

相關文章