NULL列索引失效?測試一下NULL對mysql性能的影響

最近公司規範數據庫方面的一些東西,老程序員告訴我mysql裏不許使用null,說是含null值的列無法索引,對性能影響很大。我第一次據說這個,對此將信將疑,以前用null並索引並無感受到不妥,多是數據量小吧。因而我去google了一頓,可是並無找到權威的說法。mysql

V2EX——關於null的索引不生效的傳說是真的麼?git

by shiny:
因爲數據庫的複雜性,以訛傳訛的空間很是大,快遇上中醫養生了。避免使用 NULL 的理由,在高性能MySQL裏有提到一段。建議你們多讀些書,少看網上的奇技淫巧。特地把書翻出來摘錄了下以供參考:
要儘可能避免 NULL
要儘量地把字段定義爲 NOT NULL。即便應用程序無須保存 NULL(沒有值),也有許多表包含了可空列(Nullable Column),這僅僅是由於它爲默認選項。除非真的要保存 NULL,不然就把列定義爲 NOT NULL。
MySQL難以優化引用了可空列的查詢,它會使索引、索引統計和值更加複雜。可空列須要更多的儲存空間,還須要在MySQL內部進行特殊處理。當可空列被索引的時候,每條記錄都須要一個額外的字節,還可能致使 MyISAM 中固定大小的索引(例如一個整數列上的索引)變成可變大小的索引。
即便要在表中儲存「沒有值」的字段,仍是有可能不使用 NULL 的。考慮使用 0、特殊值或空字符串來代替它。
把 NULL 列改成 NOT NULL 帶來的性能提高很小,因此除非肯定它引入了問題,不然就不要把它看成優先的優化措施。而後,若是計劃對列進行索引,就要儘可能避免把它設置爲可空。

stackoverflow——NULL in MySQL (Performance & Storage)程序員

by Arian Acosta:
Advantage of using NULLS over Empty Strings or Zeros:
1 NULL requires 1 byte
1 Empty String requires 1 byte (assuming VARCHAR)
1 Zero requires 4 bytes (assuming INT)
You start to see the savings here:
8 NULLs require 1 byte
8 Empty Strings require 8 bytes
8 Zeros require 32 bytes
On the other hand, I suggest using NULLs over empty strings or zeros, because they're more organized, portable, and require less space. To improve performance and save space, focus on using the proper data types, indexes, and queries instead of weird tricks.

中英文用戶們對此都是爭論不休,在羣裏問了一下老前輩,前輩表示mysql這個東西很玄乎,仍是本身寫性能測是最靠譜,說的好那麼開始寫吧。github

測試環境

  • mysql 5.7
  • golang 1.9.2
  • mac os 10.13.1

測試思路

  • 建兩張相似的表,有id,name,number三列,給name建索引,兩張表區別是一個容許null一個not_null
  • 隨機生成若干條數據,包含一些name爲空的數據
  • 將相同的數據插入兩個表中,區別空值是一個用null一個用‘’
  • 測試SELECT * FROM table WHERE NAME = ? 的性能

測試代碼

https://github.com/win5do/pla...golang

進入文件所在目錄運行:go test -v -run=none -bench=. -benchmemsql

測試結果

mysql5.7 mock100w條數據 null徹底沒影響
圖片描述數據庫

mysql5.5 仍是100w條
圖片描述less

儲存空間佔用也是相同的,null佔空間 ‘’一樣佔空間
圖片描述工具

寫測試代碼碰到的坑

爲何要用golang,由於最近在學習golang,經過寫代碼來加深對語言的理解。並且golang自帶測試工具,作性能測試很是方便。性能

第一個坑,之前沒用過golang鏈接數據庫,寫create語句的時候一直提示syntax error,仔細檢查了好幾遍,沒有錯誤啊。後來翻了翻文檔發現鏈接是加上multiStatements=true參數才能使用多行sql。

第二個坑就是insert語句拼接的太長會致使write pipe broken,mock50000行時沒問題,但100000行就報錯了,解決辦法就是分塊插入,10000行插一下。

第三個坑,就是query以後是要close的

結論

測試了mysql5.7和5.5版本,null對索引沒有影響,甚至容許null的還快一丟丟(或者說個人測試太過於簡單,不成立?)。不要一棒子把null打死,該用就用,null的語義化很好,配合orm使用基本無痛。好比時間列,不用null用個0000-00-00不要太蛋痛。

那句老話:

過早的優化是萬惡之源

僅憑中醫理論優化更是無可救藥

更重要的,用golang寫代碼真的很cool

相關文章
相關標籤/搜索