数据库优化、数据库基础等常用知识点总结
建表優化
1)數據庫范式
- 第一范式(1NF):強調的是列的原子性,即列不能夠再分成其他幾列。
如電話列可進行拆分—家庭電話、公司電話 - 第二范式(2NF):首先是 1NF,另外包含兩部分內容,一是表必須有主鍵;二是沒有包含在主鍵中的列必須完全依賴于主鍵,而不能只依賴于主鍵的一部分。
- 第三范式(3NF):首先是 2NF,另外非主鍵列必須直接依賴于主鍵,不能存在傳遞依賴。
比如Student表(學號,姓名,年齡,性別,所在院校,院校地址,院校電話)
這樣一個表結構,就存在上述關系。 學號–> 所在院校 --> (院校地址,院校電話)
這樣的表結構,我們應該拆開來,如下:
(學號,姓名,年齡,性別,所在院校)–(所在院校,院校地址,院校電話)
滿足這些規范的數據庫是簡潔的、結構明晰的; 同時,不會發生插入(insert)、刪除(delete)和更新(update)操作異常。
2)數據類型選擇
l 數字類型
Float和double選擇(盡量選擇float,有效位7位,而double是15位)
區分開TINYINT / INT / BIGINT,能確定不會使用負數的字段,建議添加 unsigned定義
能夠用數字類型的字段盡量選擇數字類型而不用字符串類型的
l 字符類型
char,varchar,TEXT的選擇:非萬不得已不要使用 TEXT 數據類型,定長字段,建議使用 CHAR 類型(填空格),不定長字段盡量使用 VARCHAR(自動適應長度,超過階段),且僅僅設定適當的最大長度
l 時間類型
按選擇優先級排序DATE(精確到天)、TIMESTAMP(1970開始的秒)、DATETIME(精確到時間)
l ENUM
對于狀態字段,可以嘗試使用 ENUM 來存放,但是用枚舉值是數字可能會出現問題最好不用。
l 避免使用NULL字段,很難查詢優化且占用額外索引空間
3)字符編碼
同樣的內容使用不同字符集表示所占用的空間大小會有較大的差異,所以通過使用合適的字符集,可以幫助我們盡可能減少數據量,進而減少IO操作次數。
- 純拉丁字符能表示的內容,選擇 latin1 字符編碼
- 中文可選用utf-8
- MySQL的數據類型可以精確到字段,所以當我們需要大型數據庫中存放多字節數據的時候,可以通過對不同表不同字段使用不同的數據類型來較大程度減小數據存儲量,進而降低 IO 操作次數并提高緩存命中率
Sql優化
-
只返回需要的數據
a) 不要寫SELECT *的語句
b) 合理寫WHERE子句,不要寫沒有WHERE的SQL語句。 -
盡量少做重復的工作:可以合并一些sql語句
-
適當建立索引(不是越多越好)但以下幾點會進行全表掃描
a) 左模糊查詢’%…’
b) 使用了不等操作符!=
c) or使用不當,or兩邊都必須有索引才行 可以使用union all 來鏈接兩句sql
d) In 、not in 根據情況可以用between and
e) Where子句對字段進行表達式操作
f) 對于創建的復合索引(從最左邊開始組合),查詢條件用到的列必須從左邊開始不能間隔。否則無效,復合索引的結構與電話簿類似
g) 全文索引:當于對文件建立了一個以詞庫為目錄的索引(文件大全文索引比模糊匹配效果好)
能在char、varchar、text類型的列上面創建全文索引
MySQL 5.6 Innodb引擎也能進行全文索引
搜索語法:MATCH (列名1, 列名2,…) AGAINST (搜索字符串 [搜索修飾符])
如果列類型是字符串,但在查詢時把一個數值型常量賦值給了一個字符型的列名name,那么雖然在name列上有索引,但是也沒有用到。 -
使用join代替子查詢
-
使用union代替手動創建臨時表
索引優化
一、 創建索引,以下情況不適合建立索引
- 表記錄太少
- 經常插入、刪除、修改的表
- 數據重復且分布平均的表字段
二、 復合索引
如果一個表中的數據在查詢時有多個字段總是同時出現則這些字段就可以作為復合索引
索引
索引是對數據庫表中一列或多列的值進行排序的一種結構。B+tree索引結構
原理 就是為無序存放的數據建立一個有序的對應關系,通過這個關系可以快速查找數據。
優點:
- 大大加快數據的檢索速度
- 創建唯一性索引,保證數據庫表中每一行數據的唯一性
- 可以加速表和表之間的連接
缺點: - 索引需要占物理空間。
- 當對表中的數據進行增加、刪除和修改的時候,索引也要動態的維護,降低了數據的維護速度。
索引分類:
sql語句創建索引:
- CREATE INDEX index_name ON table_name (column_name) 可以創建unique index索引。
- ALTER TABLE table_name ADD INDEX index_name (column_name) 第二種方法可以創建primary key和unique、index三種索引
注意:如果是字符串要指定長度column(長度) - drop index index_name;刪除索引
三種索引解釋 - 普通索引
- unique 唯一索引,索引列的值必須唯一,但允許有空值
- primary key主鍵索引,它是一種特殊的唯一索引,不允許有空值。
- 還可以進行組合索引
事務
數據庫事務(Database Transaction) ,是指作為單個邏輯工作單元執行的一系列操作,要么完全地執行,要么完全地不執行。
四大特征:
(1)原子性
事務必須是原子工作單元;對于其數據修改,要么全都執行,要么全都不執行。
(2)一致性
事務的一致性指的是在一個事務執行之前和執行之后數據庫都必須處于一致性狀態。事務執行的結果必須是使數據庫從一個一致性狀態變到另一個一致性狀態。
(3) 隔離性(關于事務的隔離性數據庫提供了多種隔離級別)
一個事務的執行不能干擾其它事務。即一個事務內部的操作及使用的數據對其它并發事務是隔離的,并發執行的各個事務之間不能互相干擾。
(4)持久性
事務完成之后,它對于數據庫中的數據改變是永久性的。該修改即使出現系統故障也將一直保持。
在介紹數據庫提供的各種隔離級別之前,我們先看看如果不考慮事務的隔離性,會發生的幾種問題:
- 臟讀
臟讀是指在一個事務處理過程里讀取了另一個未提交的事務中的數據。 - 不可重復讀
- 幻讀
幻讀和不可重復讀都是讀取了另一條已經提交的事務,不可重復讀重點在于update和delete,而幻讀的重點在于insert。
在可重復讀中,該sql第一次讀取到數據后,就將這些數據加鎖,其它事務無法修改這些數據,就可以實現可重復 讀了。但這種方法卻無法鎖住insert的數據,所以當事務A先前讀取了數據,或者修改了全部數據,事務B還是可以insert數據提交,這時事務A就會 發現莫名其妙多了一條之前沒有的數據,這就是幻讀,不能通過行鎖來避免。需要Serializable隔離級別 ,讀用讀鎖,寫用寫鎖,讀鎖和寫鎖互斥,這么做可以有效的避免幻讀、不可重復讀、臟讀等問題,但會極大的降低數據庫的并發能力。
現在來看看MySQL數據庫為我們提供的四種隔離級別:
① Serializable (串行化):可避免臟讀、不可重復讀、幻讀的發生。
② Repeatable read (可重復讀):可避免臟讀、不可重復讀的發生。 # 同一個查詢sql執行多次都和第一次保持一致
③ Read committed (讀已提交):可避免臟讀的發生。 # 當前讀取到最新的
④ Read uncommitted (讀未提交):最低級別,任何情況都無法保證。
在MySQL數據庫中默認的隔離級別為Repeatable read (可重復讀)。
在實際開發中:訂單并發庫存問題
使用樂觀鎖要使用到Read committed (讀已提交)這個隔離級別。其他事務下單了對庫存進行更改并提交了,并行的當前事務讀取第二遍的時候跟第一次讀取的結果保持一致,但是讀取已提交,第二遍或接下來的讀取會讀取到最新的。
select origin_stock from tb_sku where id=<sku_id>; # 這里記錄原始的庫存(需要保證最新)
update tb_sku set stock=<new_stock>, sales=<new_sales> where id=<sku_id> and stock=<origin_stock>;
鎖模式包括:
l 共享鎖:(讀取)操作創建的鎖。其他用戶可以并發讀取數據,但任何事物都不能獲取數據上的排它鎖,直到已釋放所有共享鎖。
l 排他鎖(X鎖):對數據A加上排他鎖后,則其他事務不能再對A加任任何類型的封鎖。獲準排他鎖的事務既能讀數據,又能修改數據。
l 更新鎖:
更新 (U) 鎖可以防止通常形式的死鎖。如果兩個事務獲得了資源上的共享模式鎖,然后試圖同時更新數據,則兩個事務需都要轉換共享鎖為排它 (X) 鎖,并且每個事務都等待另一個事務釋放共享模式鎖,因此發生死鎖。
若要避免這種潛 在的死鎖問題,請使用更新 (U) 鎖。一次只有一個事務可以獲得資源的更新 (U) 鎖。如果事務修改資源,則更新 (U) 鎖轉換為排它 (X) 鎖。否則,鎖轉換為共享鎖。
鎖的粒度主要有以下幾種類型:
l 行鎖: 粒度最小,并發性最高
l 頁鎖:一次鎖定一頁。25個行鎖可升級為一個頁鎖。
l 表鎖:粒度大,并發性低
l 數據庫鎖:控制整個數據庫操作
樂觀鎖: 相對悲觀鎖而言,樂觀鎖假設認為數據一般情況下不會造成沖突,所以在數據進行提交更新的時候,才會正式對數據的沖突與否進行檢測,如果發現沖突了,則讓返回用戶錯誤的信息,讓用戶決定如何去做。一般的實現樂觀鎖的方式就是記錄數據版本。
悲觀鎖: 顧名思義,就是很悲觀,每次去拿數據的時候都認為別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。傳統的關系型數據庫里邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。
引擎 MyISAM、InnoDB區別
l MyISAM類型不支持事務處理等高級處理,而InnoDB類型支持。
l MyISAM表不支持外鍵,InnoDB支持
l MyISAM鎖的粒度是表級,而InnoDB支持行級鎖定。
l MyISAM支持全文類型索引,而InnoDB不支持全文索引。(mysql 5.6后innodb支持全文索引)
MyISAM相對簡單,所以在效率上要優于InnoDB,小型應用可以考慮使用MyISAM。當你的數據庫有大量的寫入、更新操作而查詢比較少或者數據完整性要求比較高的時候就選擇innodb表。當你的數據庫主要以查詢為主,相比較而言更新和寫 入比較少,并且業務方面數據完整性要求不那么嚴格,就選擇mysiam表。
MyISAM和InnoDB索引實現:
MyISAM索引實現
MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。
l 主索引
MyISAM引擎使用B+Tree作為索引結構,葉節點的data域存放的是數據記錄的地址。
l 輔助索引
在MyISAM中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是唯一的,而輔助索引的key可以重復。
MyISAM中索引檢索的算法為首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,則取出其data域的值,然后以data域的值為地址,讀取相應數據記錄。
MyISAM的索引方式也叫做“非聚集”的,之所以這么稱呼是為了與InnoDB的聚集索引區分。
InnoDB索引實現
然InnoDB也使用B+Tree作為索引結構,但具體實現方式卻與MyISAM截然不同.
l 主索引
InnoDB表數據文件本身就是主索引。
InnoDB主索引(同時也是數據文件)的示意圖,可以看到葉節點包含了完整的數據記錄。這種索引叫做聚集索引。因為InnoDB的數據文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則MySQL系統會自動選擇一個可以唯一標識數據記錄的列作為主鍵,如果不存在這種列,則MySQL自動為InnoDB表生成一個隱含字段作為主鍵,這個字段長度為6個字節,類型為長整形。
l 輔助索引
InnoDB的所有輔助索引都引用主鍵作為data域。
聚集索引這種實現方式使得按主鍵的搜索十分高效,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然后用主鍵到主索引中檢索獲得記錄。
不同存儲引擎的索引實現方式對于正確使用和優化索引都非常有幫助,例如知道了InnoDB的索引實現后,就很容易明白
1、為什么不建議使用過長的字段作為主鍵,因為所有輔助索引都引用主索引,過長的主索引會令輔助索引變得過大。
2、用非單調的字段作為主鍵在InnoDB中不是個好主意,因為InnoDB數據文件本身是一顆B+Tree,非單調的主鍵會造成在插入新記錄時數據文件為了維持B+Tree的特性而頻繁的分裂調整,十分低效,而使用自增字段作為主鍵則是一個很好的選擇。
InnoDB索引和MyISAM索引的區別:
l 一是主索引的區別,InnoDB的數據文件本身就是索引文件。而MyISAM的索引和數據是分開的。
l 二是輔助索引的區別:InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。而MyISAM的輔助索引和主索引沒有多大區別。
紅黑樹 B樹 B+樹 B-樹
二叉查找樹(BST):
二叉排序樹或者是一棵空樹,或者是具有下列性質的二叉樹:
l 若左子樹不空,則左子樹上所有結點的值均小于它的根結點的值。
l 若右子樹不空,則右子樹上所有結點的值均大于它的根結點的值。
l 左、右子樹也分別為二叉排序樹。
l 沒有鍵值相等的節點(因此,插入的時候一定是葉子節點)。
刪除算法
l 要刪除節點是葉子節點。
l 要刪除的節點只有一個孩子(左孩子或右孩子),這種情況比較簡單,只需要將該孩子連接到當前節點的父節點即可。
l 要刪除的節點有兩個孩子,這個時候的算法就比較復雜(相比較于只有一個孩子的情況)。首先我們需要找到待刪除節點的左子樹上的最大值節點,或者右子樹上的最小值節點,然后將該節點的參數值與待刪除的節點參數值進行交換,最后刪除該節點,這樣需要刪除的參數就從該二叉樹中刪除了。
紅黑樹:
紅黑樹(Red Black Tree) 是一種自平衡二叉查找樹 :
l 每個節點或者是黑色,或者是紅色。
l 根節點是黑色。
l 每個葉子節點是黑色。
l 如果一個節點是紅色的,則它的子節點必須是黑色的。
l 從一個節點到該節點的子孫節點的所有路徑上包含相同數目的黑節點。
紅黑樹的各種操作的時間復雜度是O(logn)。
紅黑樹 vs AVL
紅黑樹的查詢性能略微遜色于AVL樹,因為他比avl樹會稍微不平衡最多一層,也就是說紅黑樹的查詢性能只比相同內容的avl樹最多多一次比較,但是,紅黑樹在插入和刪除上完爆avl樹,avl樹每次插入刪除會進行大量的平衡度計算,而紅黑樹為了維持紅黑性質所做的紅黑變換和旋轉的開銷,相較于avl樹為了維持平衡的開銷要小得多
B樹與B-樹:
B-tree樹即B樹,B即Balanced,平衡的意思。因為B樹的原英文名稱為B-tree,而國內很多人喜歡把B-tree譯作B-樹,其實,這是個非常不好的直譯,很容易讓人產生誤解。如人們可能會以為B-樹是一種樹,而B樹又是另一種樹。而事實上是,B-tree就是指的B樹。
m階B樹是一棵平衡的m路搜索樹。它是空樹,或者是滿足下列性質的樹:
l 根結點的兒子數為[2, M];
l 除根結點以外的非葉子結點的兒子數為[M/2, M]; (M/2向上取整)
l 每個結點存放至少M/2-1(取上整)和至多M-1個關鍵字;
l 非葉子結點的關鍵字個數=指向兒子的指針個數-1;
l 非葉子結點的關鍵字:K[1], K[2], …, K[X-1];且K[i] < K[i+1];
l 非葉子結點的指針:P[1], P[2], …, P[X];其中P[1]指向關鍵字小于K[1]的子樹,P[X]指向關鍵字大于K[X-1]的子樹,其它P[i]指向關鍵字屬于(K[i-1], K[i])的子樹;
l 所有葉子結點位于同一層;
B+樹:
B+樹是B-樹的變體,也是一種多路搜索樹:
其定義基本與B-樹同,除了:
l 非葉子結點的子樹指針與關鍵字個數相同;
l 非葉子結點的子樹指針P[i],指向關鍵字值屬于[K[i], K[i+1])的子樹(B-樹是開區間);
l 為所有葉子結點增加一個指針鏈;
l 所有關鍵字都在葉子結點出現;
基本SQL操作
SELECT * FROM table ORDER BY field DESC; (ASC|DESC)SELECT DISTINCT field from table where 范圍INSERT INTO table_name (column1,column2,column3,...) VALUES (value1,value2,value3,...);UPDATE table_name SET column1=value1,column2=value2,... WHERE some_column=some_value;DELETE FROM table_name WHERE some_column=some_value;LIKE 操作符
SELECT column_name(s) FROM table_name WHERE column_name LIKE pattern;IN 操作符
SELECT column_name(s) FROM table_name WHERE column_name IN (value1,value2,...);BETWEEN 操作符
SELECT column_name(s) FROM table_name WHERE column_name BETWEENJOIN
左連接,右連接,內連接
left join(左聯接): 返回包括左表中的所有記錄和右表中聯結字段相等的記錄。
right join(右聯接): 返回包括右表中的所有記錄和左表中聯結字段相等的記錄。
inner join(等值連接): 只返回兩個表中聯結字段相等的行。(默認)
UNION 操作符
UNION 操作符用于合并兩個或多個 SELECT 語句的結果集,可選ALL 重復也顯示。
創建視圖
CREATE VIEW view_name AS SELECT column_name(s) FROM table_name WHERE conditionSQL函數
Avg() Count() Max() Min() Sum()
Group By():
GROUP BY 語句用于結合聚合函數,根據一個或多個列對結果集進行分組。
SELECT column_name, aggregate_function(column_name) FROM table_name WHERE column_name operator value GROUP BY column_name;HAVING 子句可以讓我們篩選分組后的各組數據。
SELECT column_name, aggregate_function(column_name) FROM table_name WHERE column_name operator value GROUP BY column_name HAVING aggregate_function(column_name) operator value;如何查詢數據庫表結構,主鍵
desc tabl_name;建表
CREATE TABLE 表名稱(列名稱1 數據類型,....)總結
以上是生活随笔為你收集整理的数据库优化、数据库基础等常用知识点总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 后端与前端Date类型与Str
- 下一篇: mysql 42642 安装报错_1/5