建表規范
- 必須包含整數型自增主鍵
- 對于 where 查詢的字段增加索引
- 聯合索引是最左性原理,例如聯合索引是(a,b,c),在查詢時 a,ab,abc的精確匹配,都會使用索引;查詢 b,ac,c 都不會使用該索引
- 建議對創建時間字段建立索引,一般命名創建時間為ctime,修改時間為mtime
創建表的例子,實現了ctime為初次創建時間,mtime為每次更新時間
````
CREATE TABLE `test` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`score` int(1) NOT NULL,
`money` decimal(10,2) NOT NULL DEFAULT '0.00',
`balance` decimal(10,3) NOT NULL DEFAULT '0.000',
`ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`mtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
`````
字段類型
- int(10) 和 int(1) 只是MySQL中顯示顯示寬度值,不影響真正存儲的數值范圍,也就是說int(10)和int(1)的范圍都是-2147483648 ~ 2147483647
- decimal 類型用于精確位數的精度計算,因為是字符串存儲,decimal(m,d) 其中m表示顯示寬帶就有實際作用了,可以存儲m位長度的數值,d表示多少位小數。
當 decimal(10,0) 則表示可以存儲10位整數同時小數位數為0,可以理解為 精確到元。deciaml(3,2) 表示可以存儲3位數值,小數精確到2位,也就是可以精確到分;
同時3位數值是包含小數位數,所以 decimal(3,2) 的數值范圍是-9.99 ~ 9.99
- float、double 是不精確位數的浮點類型,不能用于 金額/比例計算。
- 合理利用 unsigned 類型,int 數值可以簡單記憶為正負21億,unsigned int 則為 0-42億。
- timestamp 占用4個字節,范圍是1970-01-01 00:00:00′到2037年,datetime占用8個字,節范圍是 '1000-01-01 00:00:00' 到 '9999-12-31 23:59:59'
存儲金額使用什么類型?
- 推薦使用 decimal 類型,精確指定小數位數 decimal(10,2) 應該適用于絕大多數場景,即-9999千萬~9999千萬的范圍數值,同時精確到分。
如果需要比分更小的精度可以使用 decimal(11,3)
- 有些情況下,也可以考慮采用整數存儲分,這樣的問題就是當程序在顯示/處理時都需要進行一次元單位和分單位的轉化,很容易出現bug。
- 注意事項:
當MySQL中采用decimal類型時,對應的編程語言也應該盡量使用decimal類型進行運算。
以上表中執行 `update test set balance='1.005'` ,則 balance 值最終為 `1.01` ,也就是MySQL會進行正確的四舍五入。
考慮一些場景下的精度問題,比如計算比例 1/3=0.3333... 也就是 33.33% ,但是三個元素 33.33%+33.33%+33.33%=99.99% 。
這種情況,可以考慮 子元素中采用三位小數即 33.333%,在求和中采用兩位小數精度來實現最終100.00%數值顯示目標,合理利用精確位數的四舍五入。
-
不正確的使用:
decimal(10,0) 即不要求精確小數位,則應該應該使用int(10),而不是字符串存儲的decimal.
常用字段類型規范
| 字段名 | 類型 | 說明|
| -------- | -------- |-------- |
| ad_id | char(32) | 廣告id,定長,建議索引|
| device_id | varchar(50) | device_id,一般在30個字符左右|
| ctime | timestamp/datetime | 記錄創建時間,建議索引|
| mtime | timestamp/datetime | 記錄修改時間|
| app_id | varchar(32) | 應用id|
|package_name|varchar(200) | 應用包名|
| 你的字段 | 寫到這里 | 謝謝|
使用索引
- 不使用索引會怎么樣?當記錄超過10萬行,使用where查詢特定字段內容時速度會慢到可感知。如果是前臺應用,會出現超時,慢查詢堆積等。
- 合理利用自增主鍵id,作為關聯id,查詢盡量指定主鍵id查詢,效率最高。
- 優先考慮unique唯一索引,效率最高。
- 通過explain select .... 來查看索引使用效果。
- 表上索引多,會導致 insert 寫入變慢,update 操作會引發索引更新。
- 提高查詢效率的辦法還有 大表拆小表,分表,分庫等,別忘記了恰當的使用redis等緩存。
- 當對varchar(50)這樣的字段建立索引時,可以考慮只對前20個字符進行索引,這樣可以提高索引查詢效率,同時節約內存。
其他建議
-
建立數據庫索引,一定不要和字段名一致 。推薦使用 `i_字段1_字段2` 索引命名方式。
-
刪除索引/刪除字段前,運維需要對表進行備份。
-
需要對針對的SQL進行explain測試,新增索引后,確認索引生效。
- 需要看 key 值是否命中設置的索引值
- 如果SQL中where 包含了4個字段,則可以建立4個字段的聯合索引
- 需要看掃描表行數 rows 值是否大幅減小
- 索引字段上使用函數,會導致索引無效
-
索引是最左性原理,例如聯合索引是(a,b,c),在查詢時 a,ab,abc的精確匹配,都會使用索引;查詢 b,ac,c 都不會使用該索引
-
對外服務接口SQL執行效率優先
- 避免使用視圖
- 避免使用外鍵
- 避免使用ORM事務
-
設置連接超時時間,防止滿連接過多占滿連接
-
頻繁更新的表,不要加太多索引
-
如果一張表超過2000萬行,加索引很可能會失敗,解決方案是導出老數據到bak表,原表刪除數據,再加索引。
-
關注自己系統的慢查詢
-
log型的數據庫表,自增id列應該采用bigint,防止達到int32的上限,僅為了節省空間而采用int32帶來的收益微乎期微,不值得為止冒險