MySQL 複習(一)類型介紹

MySQL基本介紹

SQL 是Structure Query Language(結構化查詢語言)的縮寫,它是使用關係模型的數據庫應用語言。SQL的擴展語言有MySQL、SQL Service等。

基本架構

內容參考
全局圖

SQL 語句分類

SQL 語句主要可以劃分爲以下3 個類別:

  • DDL(Data Definition Languages)語句
    數據定義語言,這些語句定義了不同的數據段、數據庫、表、列、索引等數據庫對象的定義。常用的語句關鍵字主要包括create、drop、alter等。
  • DML(Data Manipulation Language)語句
    數據操縱語句,用於添加、刪除、更新和查詢數據庫記錄,並檢查數據完整性,常用的語句關鍵字主要包括insert、delete、udpate 和select 等。
  • DCL(Data Control Language)語句
    數據控制語句,用於控制不同數據段直接的許可和訪問級別的語句。這些語句定義了數據庫、表、字段、用戶的訪問權限和安全級別。主要的語句關鍵字包括grant、revoke 等。

MySQL在線幫助文檔

  • HELP contents 查看MySQL命令的使用。
    help contents查看所有的類型。當需要具體到某個類的時候,可以使用HELP 類別名。eg:HELP ‘Data Type’ 查看所有的數據類型的使用方法。根據全部的一級一級的篩選查詢自己想要的內容

  • SHOW VARIABLES
    可以通過SHOW VARIABLES語句查看系統變量及其值。eg:SHOW VARIABLES like ‘%show%’。默認的級別是session,此外還有global, SHOW GLOBAL VARIABLES。session就是當前會話級別的查詢,global就是全局級別。

  • SHOW STATUS
    在MySQL中,我們可以使用SHOW STATUS指令語句來查看MySQL服務器的狀態信息。當我們希望能夠「按需查看」一部分狀態信息。這個時候,我們可以在show status語句後加上對應的like子句。例如,我們想要查看當前MySQL啓動後的運行時間,我們可以執行如下語句:show status like ‘%select%’。他也是有session級別和global級別的,使用方法同SHOW VARIABLES 一樣。

  • select version() 查看SQL的版本號
    select now() 查看當前時間

SQL的類型分類

整數類型

  • 整數寬度
    對於整型數據,MySQL還支持在類型名稱後面的小括號內指定顯示寬度,例如int(5)表示當數值寬度小於5位的時候在數字前面填滿寬度,如果不顯示指定寬度則默認爲int(11)。設置了寬度限制後,如果插入大於寬度限制的值,會不會截斷或者插不進去報錯?答案是肯定的:不會對插入的數據有任何影響,還是按照類型的實際精度進行保存

  • UNSIGNED屬性
    所有的整數類型都有一個可選屬性UNSIGNED(無符號),如果需要在字段裏面保存非負數或者需要較大的上限值時,可以用此選項,它的取值範圍是正常值的下限取0,上限取原值的2倍,例如,tinyint有符號範圍是-128~+127,而無符號範圍是0~255。。如果一個列指定爲zerofill,則MySQL自動爲該列添加UNSIGNED屬性

  • AUTO_INCREMENT屬性
    整數類型還有一個屬性:AUTO_INCREMENT。在需要產生唯一標識符或順序值時, 可利用此屬性,這個屬性只用於整數類型。AUTO_INCREMENT 值一般從1 開始,每行增加1。 在插入NULL 到一個AUTO_INCREMENT 列時,MySQL 插入一個比該列中當前最大值大1 的 值。一個表中最多隻能有一個AUTO_INCREMENT列。對於任何想要使用AUTO_INCREMENT 的 列,應該定義爲NOT NULL,並定義爲PRIMARY KEY 或定義爲UNIQUE 鍵。
    查看自增的信息show variables like '%increment%'

  • sql_mode使用
    一、 有些時候在你添加數據的時候,明明會出現數據溢出的問題,卻依然能正常的操作,只是數據卻不是自己想要的。這個時候可以看一下sql_mode的設置。sql_mode的基本命令命令select @@sql_mode set @@sql_mode=TRADITIONAL。 參考
    二、使用方法解決問題

    • 可以完成不同嚴格程度的數據校驗,有效地保障數據準確性。
    • 應用在不同數據庫之間進行遷移時,則不需要對業務SQL 進行較大的修改。
    • 在不同數據庫之間進行數據遷移之前,通過設置SQL Mode 可以使MySQL上的數據更方便地遷移到目標數據庫中。

小數類型

  • 分類
    MySQL 分爲兩種方式:浮點數和定點數。浮點數包括float(單精度)和double(雙精度),而定點數則只有decimal一種表示。定點數在MySQL內部以字符串形式存放,比浮點數更精確,適合用來表示貨幣等精度高的數據。

  • 使用
    浮點數和定點數都可以用類型名稱後加“(M,D)”的方式來進行表示,“(M,D)”表示該值一共顯示M 位數字(整數位+小數位),其中D位位於小數點後面,M 和D 又稱爲精度和標度。
    MySQL 保存值時進行四捨五入,因此如果在float(7,4)列內插入999.00009,近似結果是999.0001。值得注意的是,浮點數後面跟“(M,D)”的用法是非標準用法,如果要用於數據庫的遷移,則最好不要這麼使用

  • 注意
    float 和double在不指定精度時,默認會按照實際的精度(由實際的硬件和操作系統決定) 來顯示,而decimal在不指定精度時,默認的整數位爲10,默認的小數位爲0。

BIT(位)類型

  • 介紹
    對於BIT(位)類型,用於存放位字段值,BIT(M)可以用來存放多位二進制數,M 範圍從1~64,如果不寫則默認爲1位。

  • 使用
    對於位字段,如果直接使用SELECT命令看不到結果,可以用bin()(顯示爲二進制格式)或者hex()(顯示爲十六進制格式)函數進行讀取

時間類型

  • 分類
類型 字節 最小值 最大值 零值表示
DATE 4 1000-01-01 9999-12-31 0000-00-00
DATETIME 8 1000-01-01 00:00:00 9999-12-31 23:59:59 0000-00-00 00:00:00
TIMESTAMP 4 19700101080001 2038年的某個時刻 00000000000000
TIME 3 -838:59:59 838:59:59 00:00:00
YEAR 1 1901 2155 0000
  • 這些數據類型的主要區別如下:

    • DATE來表示年月。
    • DATETIME表示年月日時分秒
    • TIME 來表示時分秒
    • 通常使用TIMESTAMP經常插入或者更新日期爲當前系統時間。TIMESTAMP 值返回後顯示爲“YYYY-MM-DD HH:MM:SS”格式的字符串,顯示寬度固定爲19個字符。如果想要獲得數字值,應在TIMESTAMP列添加+0。
    • YEAR表示年份,它比DATE佔用更少的空間。YEAR有2位或4位格式的年。默認是4位格式。在4位格式中,允許的值是1901~2155 和0000。在2位格式中,允許的值是70~69,表示從1970~2069年。MySQL以YYYY 格式顯示YEAR值。
  • 使用
    DATETIME和TIMESTAMP可以設置CURRENT_TIME默認值爲當前系統時間。在添加當前時間時,使用函數now()。

insert into t1(id7) values(now());
alter table t1 modify `id5` timestamp NULL DEFAULT CURRENT_TIMESTAMP;
  • TIMESTAMP和DATETIEM區別

  • TIMESTAMP的插入和查詢都受當地時區的影響,更能反應出實際的日期。而DATETIME則只能反應出插入時當地的時區,其他時區的人查看數據必然會有誤差的。

  • TIMESTAMP佔用的內存是是DATETIME的一半。TIMESTAMP存儲的是從1970年1月1日午夜以來的秒數,佔用4個字節,DATETIME存儲的格式YYYYMMDDHHMMSS格式,佔用8個字節。

  • 案例解釋:show variables like 'time_zone’當時的時區爲SYSTEM,即東八區。時區改爲東九區,添加數據,兩個字段的屬性如下'id5' timestamp NULL DEFAULT CURRENT_TIMESTAMP, 'id6' datetime DEFAULT CURRENT_TIMESTAMP此時兩個時間是一致的,都是東九區的時間;然後將時區改爲原先的東八區,發現id5時間又變成了東八區的時間,而id6還是原先的九區時間。

  • 相關時區命令

-- 查看時區
show variables like 'time_zone';
-- 查看時區
select @@time_zone;
-- 修改時區
set time_zone='+9:00';

時區的值爲“SYSTEM”,這個值默認是和主機的時區值一致的,因爲我們在中國,這裏的“SYSTEM”實際是東八區(+8:00)。

CHAR & VARCHAR

CHAR 和VARCHAR 很類似,都用來保存MySQL 中較短的字符串。兩者的存儲數據範圍不一樣。另外在存數據的時候,CHAR列刪除了尾部的空格,而VARCHAR 則保留這些空格。

CREATE TABLE vc (v VARCHAR(4), c CHAR(4));
INSERT INTO vc VALUES ('ab ', 'ab ');

查看長度

select length(v),length(c) from vc;

枚舉類型ENUM

有時候可以使用枚舉類型替代字符類型。枚舉可以把一些不重複的字符串存儲爲成一個預定義的集合。MySQL在內部會將每個值所在枚舉的位置保存爲整數,並且在表的.fm文件中保存“數字-字符串”映射關係的查找表。

create table enum_test(
	e ENUM('JAVA','C++','C','GO','RUBY') NOT NULL DEFAULT ''
);

insert insert enum_test(e) values('JAVA'),('C++');

這三列實際存儲的是整數,而不是字符串。可以通過在數字上下文環境檢索看到這個雙重屬性。

select e + 0 from enum_test;

所以在使用的時候,如果使用數字作爲枚舉值那麼就會造成混亂。另外枚舉在排序的時候使用的是內部存儲的整數進行排序的,但是這個可以通過FIELD()函數指定顯式的指定排序。

select * from enum_test order by FIELD(e, 'GO','C','C++','JAVA','RUBY');
缺點

枚舉的內容是固定,如果你需要添加一個枚舉或者刪除一個枚舉,則需要使用ALTER TABLE。如果修改的枚舉類有使用,則會造成現有數據的混亂。所以在使用的時候確定好這個枚舉值是否會經常的改變。

優化注意點

類型選擇

更小的通常更好

應該儘量使用可以正確存儲數據類型的最小數據類型。更小的數據類型通常佔用更少的內存緩存、CPU、磁盤,在處理的時候使用CPU的週期更少。例如:若是存儲的字符是固定的長度,則使用char則比varchar更好

簡單就好

簡單數據類型的操作使用的CPU更少。例如整型比字符操作代價更低。因爲字符集和校對規則(排序規則)使字符比較比整型比較更復雜。
例子:① 使用MySQL的內建類型存儲時間(date、TIMESTAMP、DATETIME等),而非字符串。② 存儲IP使用整型。

儘量避免NULL

儘量指定列爲NOT NULL,除非真的需要存儲NULL。
當可爲NULL的列作爲索引的時候,每個索引記錄都需要一個額外的字節。例外:InnoDB使用單獨的位(bit)存儲NULL值,所以對於稀疏數據具有很好的空間利用率。

選擇標識列

標識列的類型選擇是很重要的,標識列一般會作爲關聯列,或者查詢其他相關的表內容,標識列不同的類型,實現的效果性能會有差異。
① 標識列的數據類型應當和關聯表中對應列的數據類型一致
② 選擇的時候要考慮存儲類型還有存儲類型在MySQL計算和比較的過程。
③ 標識列的類型儘量不要選擇ENUM和SET類型。比較好的選擇是使用整數類型。另外字符類型也不太建議,消耗內存,比較比整數類型慢。
④ 對於完全“隨機”的字符串需要多加註意,如MD5()、SHA1()、UUID()等。這些函數產生的字符會隨機分佈在很大的內存中,會導致INSERT和一些SELECT很慢。
如果存儲UUID值可以移除’-’;或者用HEX()函數轉換UUID爲16位字節的數字,並且存在在BINARY(16)列中,檢索的時候使用HEX()函數格式化爲十六進制格式。

MySQL schema設計注意點

太多列

MySQL在存儲引擎API工作的時候需要在服務層和存儲引擎層之間通過行緩衝格式拷貝數據,然後在服務器層將緩衝內容轉換成各個行。

太多的關聯

全能的枚舉

注意防止過度的使用枚舉,枚舉的類型太多會使結構凌亂,同時如果枚舉的值經常變化會給數據庫帶來壓力。

其他(IP和UUID的處理案例)


-- 創建表
CREATE TABLE `test` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'PK',
  `ip` int(12) unsigned NOT NULL,
  `uuid` binary(16) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 添加數據,其中INET_ATON將IP解析爲整型類型,UNHEX解析爲二進制
INSERT INTO `test` ( `ip`, `uuid`)
VALUES
	(INET_ATON('255.255.255.255'), UNHEX(REPLACE(UUID(),'-','')));

-- 查詢的時候,將IP和UUID都要反解析
select HEX(uuid),INET_NTOA(ip) from test where id = 1;

提高ALTER TABLE 速度

MySQL的ALTER TABLE 操作對大表的性能來說是個大問題。MySQL大部分修改表結構都是新建一個新的結構的空表,從舊錶中查詢出所有的數據插入新表,然後刪除舊錶。這個操作很長時間,如果內存不足但是表有特別的大,還有很多的索引,那麼這個時間就更長了。
並不是所有的ALTER TABLE操作引起新建表。比如設置列的默認值,有兩種方法

-- 修改默認值,這個方法是很快的,直接修改的是.fm文件,沒有表的重建操作
alter table fcm_purchase_ticket alter column `certificate_import_status` set default 0;

-- 這種方法,會引起表的操作,耗時更長
alter table fcm_purchase_ticket modify column `certificate_import_status` NOT NULL default 0;

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章