亚洲综合原千岁中文字幕_国产精品99久久久久久久vr_无码人妻aⅴ一区二区三区浪潮_成人h动漫精品一区二区三

主頁 > 知識庫 > MySQL數字類型自增的坑

MySQL數字類型自增的坑

熱門標簽:大豐地圖標注app 呂梁外呼系統 html地圖標注并導航 400電話辦理服務價格最實惠 南太平洋地圖標注 北京金倫外呼系統 400電話變更申請 武漢電銷機器人電話 催天下外呼系統

在進行表結構設計時,數字類型是最為常見的類型之一,但要用好數字類型并不如想象得那么簡單,比如:

  • 怎么設計一個互聯網海量并發業務的自增主鍵?用 INT 就夠了?
  • 怎么設計賬戶的余額?用 DECIMAL 類型就萬無一失了嗎?

以上全錯!

數字類型看似簡單,但在表結構架構設計中很容易出現上述“設計上思考不全面”的問題(特別是在海量并發的互聯網場景下)

數字類型

整數類型

MySQL 數據庫支持 SQL 標準支持的整型類型:INT、SMALLINT。此外,MySQL 數據庫也支持諸如 TINYINT、MEDIUMINT 和 BIGINT 整型類型(表 1 顯示了各種整型所占用的存儲空間及取值范圍):

MySQL數據類型 含義(有符號)
tinyint(m) 1個字節 范圍(-128~127)
smallint(m) 2個字節 范圍(-32768~32767)
mediumint(m) 3個字節 范圍(-8388608~8388607)
int(m) 4個字節 范圍(-2147483648~2147483647)
bigint(m) 8個字節 范圍(+-9.22*10的18次方)

在整型類型中,有 signed 和 unsigned 屬性,其表示的是整型的取值范圍,默認為 signed。在設計時,我不建議你刻意去用 unsigned 屬性,因為在做一些數據分析時,SQL 可能返回的結果并不是想要得到的結果。

來看一個“銷售表 sale”的例子,其表結構和數據如下。這里要特別注意,列 sale_count 用到的是 unsigned 屬性(即設計時希望列存儲的數值大于等于 0):

mysql> SHOW CREATE TABLE sale\G

*************************** 1. row ***************************

       Table: sale

Create Table: CREATE TABLE `sale` (

  `sale_date` date NOT NULL,

  `sale_count` int unsigned DEFAULT NULL,

  PRIMARY KEY (`sale_date`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

1 row in set (0.00 sec)


mysql> SELECT * FROM sale;

+------------+------------+

| sale_date  | sale_count |

+------------+------------+

| 2020-01-01 |      10000 |

| 2020-02-01 |       8000 |

| 2020-03-01 |      12000 |

| 2020-04-01 |       9000 |

| 2020-05-01 |      10000 |

| 2020-06-01 |      18000 |

+------------+------------+

6 rows in set (0.00 sec)

其中,sale_date 表示銷售的日期,sale_count 表示每月的銷售數量。現在有一個需求,老板想要統計每個月銷售數量的變化,以此做商業決策。這條 SQL 語句需要應用到非等值連接,但也并不是太難寫:

SELECT 

    s1.sale_date, s2.sale_count - s1.sale_count AS diff

FROM

    sale s1

        LEFT JOIN

    sale s2 ON DATE_ADD(s2.sale_date, INTERVAL 1 MONTH) = s1.sale_date

ORDER BY sale_date;

然而,在執行的過程中,由于列 sale_count 用到了 unsigned 屬性,會拋出這樣的結果:

ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(`test`.`s2`.`sale_count` - `test`.`s1`.`sale_count`)'

可以看到,MySQL 提示用戶計算的結果超出了范圍。其實,這里 MySQL 要求 unsigned 數值相減之后依然為 unsigned,否則就會報錯。

為了避免這個錯誤,需要對數據庫參數 sql_mode 設置為 NO_UNSIGNED_SUBTRACTION,允許相減的結果為 signed,這樣才能得到最終想要的結果:

mysql> SET sql_mode='NO_UNSIGNED_SUBTRACTION';

Query OK, 0 rows affected (0.00 sec)

SELECT


    s1.sale_date,

    IFNULL(s2.sale_count - s1.sale_count,'') AS diff

FROM

    sale s1

    LEFT JOIN sale s2

    ON DATE_ADD(s2.sale_date, INTERVAL 1 MONTH) = s1.sale_date

ORDER BY sale_date;


+------------+-------+

| sale_date  | diff  |

+------------+-------+

| 2020-01-01 |       |

| 2020-02-01 | 2000  |

| 2020-03-01 | -4000 |

| 2020-04-01 | 3000  |

| 2020-05-01 | -1000 |

| 2020-06-01 | -8000 |

+------------+-------+

6 rows in set (0.00 sec)

浮點類型和高精度型

除了整型類型,數字類型常用的還有浮點和高精度類型。
MySQL 之前的版本中存在浮點類型 Float 和 Double,但這些類型因為不是高精度,也不是 SQL 標準的類型,所以在真實的生產環境中不推薦使用,否則在計算時,由于精度類型問題,會導致最終的計算結果出錯。
更重要的是,從 MySQL 8.0.17 版本開始,當創建表用到類型 Float 或 Double 時,會拋出下面的警告:MySQL 提醒用戶不該用上述浮點類型,甚至提醒將在之后版本中廢棄浮點類型

Specifying number of digits for floating point data types is deprecated and will be removed in a future release

而數字類型中的高精度 DECIMAL 類型可以使用,當聲明該類型列時,可以(并且通常必須要)指定精度和標度,例如:

salary DECIMAL(8,2)

其中,8 是精度(精度表示保存值的主要位數),2 是標度(標度表示小數點后面保存的位數)。通常在表結構設計中,類型 DECIMAL 可以用來表示用戶的工資、賬戶的余額等精確到小數點后 2 位的業務。

然而,在海量并發的互聯網業務中使用,金額字段的設計并不推薦使用 DECIMAL 類型,而更推薦使用 INT 整型類型(下文就會分析原因)。

業務表結構設計實戰

整型類型與自增設計

在真實業務場景中,整型類型最常見的就是在業務中用來表示某件物品的數量。例如上述表的銷售數量,或電商中的庫存數量、購買次數等。在業務中,整型類型的另一個常見且重要的使用用法是作為表的主鍵,即用來唯一標識一行數據。
整型結合屬性 auto_increment,可以實現自增功能,但在表結構設計時用自增做主鍵,希望你特別要注意以下兩點,若不注意,可能會對業務造成災難性的打擊:

  • 用 BIGINT 做主鍵,而不是 INT;
  • 自增值并不持久化,可能會有回溯現象(MySQL 8.0 版本前)。

從表 1 可以發現,INT 的范圍最大在 42 億的級別,在真實的互聯網業務場景的應用中,很容易達到最大值。例如一些流水表、日志表,每天 1000W 數據量,420 天后,INT 類型的上限即可達到。
因此,用自增整型做主鍵,一律使用 BIGINT,而不是 INT。不要為了節省 4 個字節使用 INT,當達到上限時,再進行表結構的變更,將是巨大的負擔與痛苦。
那這里又引申出一個有意思的問題:如果達到了 INT 類型的上限,數據庫的表現又將如何呢?是會重新變為 1?我們可以通過下面的 SQL 語句驗證一下:

mysql> CREATE TABLE t (

    ->     a INT AUTO_INCREMENT PRIMARY KEY

    -> );


mysql> INSERT INTO t VALUES (2147483647);

Query OK, 1 row affected (0.01 sec)


mysql> INSERT INTO t VALUES (NULL);

ERROR 1062 (23000): Duplicate entry '2147483647' for key 't.PRIMARY'

可以看到,當達到 INT 上限后,再次進行自增插入時,會報重復錯誤,MySQL 數據庫并不會自動將其重置為 1。
第二個特別要注意的問題是,MySQL 8.0 版本前,自增不持久化,自增值可能會存在回溯問題!

mysql> SELECT * FROM t;

+---+

| a |

+---+

| 1 |

| 2 |

| 3 |

+---+

3 rows in set (0.01 sec)


mysql> DELETE FROM t WHERE a = 3;

Query OK, 1 row affected (0.02 sec)


mysql> SHOW CREATE TABLE t\G

*************************** 1. row ***************************

       Table: t

Create Table: CREATE TABLE `t` (

  `a` int NOT NULL AUTO_INCREMENT,

  PRIMARY KEY (`a`)

) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

1 row in set (0.00 sec

可以看到,在刪除自增為 3 的這條記錄后,下一個自增值依然為 4(AUTO_INCREMENT=4),這里并沒有錯誤,自增并不會進行回溯。但若這時數據庫發生重啟,那數據庫啟動后,表 t 的自增起始值將再次變為 3,即自增值發生回溯。具體如下所示:

mysql> SHOW CREATE TABLE t\G

*************************** 1. row ***************************

       Table: t

Create Table: CREATE TABLE `t` (

  `a` int NOT NULL AUTO_INCREMENT,

  PRIMARY KEY (`a`)

) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

1 row in set (0.00 s

若要徹底解決這個問題,有以下 2 種方法:

  • 升級 MySQL 版本到 8.0 版本,每張表的自增值會持久化;
  • 若無法升級數據庫版本,則強烈不推薦在核心業務表中使用自增數據類型做主鍵。

其實,在海量互聯網架構設計過程中,為了之后更好的分布式架構擴展性,不建議使用整型類型做主鍵,更為推薦的是字符串類型。

資金字段設計

在用戶余額、基金賬戶余額、數字錢包、零錢等的業務設計中,由于字段都是資金字段,通常程序員習慣使用 DECIMAL 類型作為字段的選型,因為這樣可以精確到分,如:DECIMAL(8,2)。

CREATE TABLE User (

  userId BIGINT AUTO_INCREMENT,

  money DECIMAL(8,2) NOT NULL,

  ......

)

在海量互聯網業務的設計標準中,并不推薦用 DECIMAL 類型,而是更推薦將 DECIMAL 轉化為 整型類型。也就是說,資金類型更推薦使用用分單位存儲,而不是用元單位存儲。如1元在數據庫中用整型類型 100 存儲。

金額字段的取值范圍如果用 DECIMAL 表示的,如何定義長度呢?因為類型 DECIMAL 是個變長字段,若要定義金額字段,則定義為 DECIMAL(8,2) 是遠遠不夠的。這樣只能表示存儲最大值為 999999.99,百萬級的資金存儲。

用戶的金額至少要存儲百億的字段,而統計局的 GDP 金額字段則可能達到數十萬億級別。用類型 DECIMAL 定義,不好統一。
另外重要的是,類型 DECIMAL 是通過二進制實現的一種編碼方式,計算效率遠不如整型來的高效。因此,推薦使用 BIG INT 來存儲金額相關的字段。

字段存儲時采用分存儲,即便這樣 BIG INT 也能存儲千兆級別的金額。這里,1兆 = 1萬億。

這樣的好處是,所有金額相關字段都是定長字段,占用 8 個字節,存儲高效。另一點,直接通過整型計算,效率更高。
注意,在數據庫設計中,我們非常強調定長存儲,因為定長存儲的性能更好。

我們來看在數據庫中記錄的存儲方式,大致如下:

若發生更新,記錄 1 原先的空間無法容納更新后記錄 1 的存儲空間,因此,這時數據庫會將記錄 1 標記為刪除,尋找新的空間給記錄1使用,如:

上圖中*記錄 1 表示的就是原先記錄 1 占用的空間,而這個空間后續將變成碎片空間,無法繼續使用,除非人為地進行表空間的碎片整理。

那么,當使用 BIG INT 存儲金額字段的時候,如何表示小數點中的數據呢?其實,這部分完全可以交由前端進行處理并展示。作為數據庫本身,只要按分進行存儲即可。

到此這篇關于MySQL數字類型自增的坑的文章就介紹到這了,更多相關MySQL數字類型自增內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • MySQL中日期型單行函數代碼詳解
  • Mysql 日期格式化及復雜日期區間查詢
  • MySQL 生成隨機數字、字符串、日期、驗證碼及 UUID的方法
  • MySQL關于字符串中數字排序的問題分析
  • MySQL實例精講單行函數以及字符數學日期流程控制

標簽:徐州 迪慶 無錫 自貢 西寧 麗水 南充 龍巖

巨人網絡通訊聲明:本文標題《MySQL數字類型自增的坑》,本文關鍵詞  MySQL,數字,類型,自增,的,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《MySQL數字類型自增的坑》相關的同類信息!
  • 本頁收集關于MySQL數字類型自增的坑的相關信息資訊供網民參考!
  • 推薦文章
    国产高清在线精品一区二区| 四虎论坛| 精品视频在线观看视频免费视频| 久久精品免视看国产成人2021| 日韩欧美一及在线播放| 久久国产影视免费精品| 久久国产精品自线拍免费| 99色播| 四虎影视久久| 韩国三级一区| 在线观看成人网 | 国产国语对白一级毛片| 韩国三级香港三级日本三级| 欧美1卡一卡二卡三新区| 国产视频久久久久| 欧美另类videosbestsex视频| 国产网站在线| 999久久66久6只有精品| 欧美1区| 欧美大片a一级毛片视频| 国产精品免费久久| 天堂网中文在线| 日韩专区一区| 色综合久久天天综合绕观看| 欧美18性精品| 香蕉视频久久| 日韩一级黄色| 亚洲精品中文一区不卡| 在线观看成人网 | 日韩中文字幕一区二区不卡| 九九精品在线| 成人免费观看网欧美片| 黄视频网站免费看| 日本特黄特色aa大片免费| 日韩专区在线播放| 91麻豆精品国产自产在线| 美女被草网站| 欧美爱色| 免费一级片在线观看| 中文字幕一区二区三区 精品 | 久久成人综合网| 高清一级毛片一本到免费观看| 亚洲精品久久久中文字| 日韩免费在线视频| 日韩在线观看视频网站| 日本特黄特黄aaaaa大片| 久久国产精品永久免费网站| 日日日夜夜操| 韩国毛片免费| 欧美另类videosbestsex视频| 午夜在线亚洲| 黄视频网站在线观看| 九九久久99| 99久久精品费精品国产一区二区| 好男人天堂网 久久精品国产这里是免费 国产精品成人一区二区 男人天堂网2021 男人的天堂在线观看 丁香六月综合激情 | 国产91素人搭讪系列天堂| 日韩欧美一及在线播放| 国产不卡在线播放| 在线观看成人网| 香蕉视频久久| 亚洲天堂在线播放| 日本伦理片网站| 可以免费看毛片的网站| 精品美女| 久久久成人影院| 一级片片| 亚洲第一色在线| 四虎影视库| 亚欧视频在线| 欧美另类videosbestsex视频| 欧美一区二区三区在线观看| 国产国语对白一级毛片| 黄视频网站免费看| 免费一级片在线观看| 国产麻豆精品视频| 美女免费黄网站| 精品视频在线看| 成人影院一区二区三区| 高清一级淫片a级中文字幕| 日本在线播放一区| 天天做日日爱夜夜爽| a级黄色毛片免费播放视频| 韩国妈妈的朋友在线播放| 天天色色色| 国产综合成人观看在线| 中文字幕一区二区三区精彩视频| 成人免费福利片在线观看| 久久精品人人做人人爽97| 日韩中文字幕一区| 欧美电影免费| 日本久久久久久久 97久久精品一区二区三区 狠狠色噜噜狠狠狠狠97 日日干综合 五月天婷婷在线观看高清 九色福利视频 | 成人高清护士在线播放| 黄色短视频网站| 中文字幕一区二区三区 精品 | 久草免费在线视频| 久久国产精品只做精品| 欧美另类videosbestsex高清| 精品国产三级a| 欧美日本免费| 久久99这里只有精品国产| 中文字幕Aⅴ资源网| 欧美a级片免费看| 亚洲第一页色| 中文字幕一区二区三区 精品| 九九精品久久| 国产视频在线免费观看| 国产一区二区精品在线观看| 日本久久久久久久 97久久精品一区二区三区 狠狠色噜噜狠狠狠狠97 日日干综合 五月天婷婷在线观看高清 九色福利视频 | 日韩在线观看视频黄| 精品久久久久久免费影院| 黄视频网站在线看| 国产精品自拍一区| 精品在线观看国产| 欧美另类videosbestsex| 青青青草影院 | 国产91精品系列在线观看| 国产91精品一区二区| 九九精品久久| 国产伦精品一区二区三区在线观看| 亚洲女人国产香蕉久久精品| 国产91丝袜高跟系列| 欧美激情一区二区三区视频高清| 日韩在线观看免费| 精品视频在线观看视频免费视频| 亚洲第一页乱| 九九干| 国产成a人片在线观看视频| 免费国产在线观看| 国产精品1024在线永久免费| 精品视频在线观看一区二区| 亚欧成人毛片一区二区三区四区 | 好男人天堂网 久久精品国产这里是免费 国产精品成人一区二区 男人天堂网2021 男人的天堂在线观看 丁香六月综合激情 | 91麻豆爱豆果冻天美星空| 欧美另类videosbestsex高清| 欧美夜夜骑 青草视频在线观看完整版 久久精品99无色码中文字幕 欧美日韩一区二区在线观看视频 欧美中文字幕在线视频 www.99精品 香蕉视频久久 | 日韩中文字幕在线播放| 免费的黄视频| 日韩欧美一二三区| 成人免费网站视频ww| 一级女人毛片人一女人| 欧美一级视频免费| 午夜激情视频在线播放| 九九热国产视频| 欧美激情在线精品video| 欧美1卡一卡二卡三新区| 99久久精品国产免费| 亚洲精品久久玖玖玖玖| 国产一级生活片| 国产不卡高清在线观看视频| 久久国产一区二区| 九九久久国产精品| 国产亚洲男人的天堂在线观看| 欧美a级大片| 国产视频在线免费观看| 精品国产一区二区三区国产馆| 国产一级强片在线观看| 青青久在线视频| 成人a大片高清在线观看| 欧美国产日韩一区二区三区| 天天做日日爱| 黄色免费网站在线| 国产视频久久久| 麻豆网站在线看| 国产成人女人在线视频观看 | 日韩av片免费播放| 久久久成人影院| 韩国三级香港三级日本三级la| 国产成人精品影视| 日本在线不卡视频| 免费的黄色小视频| 欧美激情一区二区三区视频高清| 999精品在线| 日韩在线观看网站| 91麻豆国产| 天天做日日爱夜夜爽| 欧美激情影院| 国产成人啪精品| 精品在线视频播放| 精品视频免费看| 天天做日日爱| 日本在线不卡免费视频一区| 国产极品精频在线观看| 青青青草影院| 亚洲第一页色| 成人免费一级纶理片| 国产成人精品综合久久久| 四虎影视库| 久久国产精品自由自在| 精品视频免费在线| 精品国产一区二区三区久| 日本特黄特色aa大片免费| 亚洲第一页乱| 国产视频一区在线| 91麻豆精品国产自产在线观看一区| 亚欧视频在线| 999精品在线| 国产极品精频在线观看| 欧美激情在线精品video| 国产伦理精品| 99热精品一区|