Mysql是關係數據庫。mysql
範式設計主要是避免冗餘,以及數據不一致。反範式設計主要是避免多表鏈接,增長了冗餘。面試
主鍵是一個表中一行數據的惟一標識。 外鍵則是值某一列的鍵值是其餘表的主鍵,外鍵的做用通常用來做爲兩錶鏈接的鍵,而且保證數據的一致性。redis
數據庫的鎖用來進行併發控制,排它鎖也叫寫鎖,共享鎖也叫行鎖,根據不一樣粒度能夠分爲行鎖和表鎖。sql
存儲過程是對sql語句進行預編譯而且以文件形式包裝爲一個能夠快速執行的程序。可是缺點是不易修改,稍微改動語句就須要從新開發儲存過程,優勢是執行效率快。視圖就是對其餘一個或多個表進行從新包裝,是一個外觀模式,對視圖數據的改動也會影響到數據報自己。數據庫
事務的四個性質:原子性,一致性,持久性,隔離性。緩存
原子性:一個事務中的操做要麼所有成功要麼所有失敗。服務器
一致性:事務執行成功的狀態都是一致的,即便失敗回滾了,也應該和事務執行前的狀態是一致的。數據結構
隔離性:兩個事務之間互不相干,不能互相影響。架構
事務的隔離級別 讀未提交:事務A和事務B,A事務中執行的操做,B也能夠看獲得,由於級別是未提交讀,別人事務中還沒提交的數據你也看獲得。這是沒有任何併發措施的級別,也是默認級別。這個問題叫作髒讀,爲了解決這個問題,提出了讀已提交。併發
讀已提交:事務A和B,A中的操做B看不到,只有A提交後,在B中才看獲得。雖然A的操做B看不到,可是B能夠修改A用到的數據,致使A讀兩次的數據結果不一樣。這就是不可重讀問題。
可重複讀:事務A和B,事務A和B,A在數據行上加讀鎖,B雖然看獲得可是改不了。因此是可重複讀的,可是A的其餘行仍然會被B訪問並修改,因此致使了幻讀問題。
序列化:數據庫強制事務A和B串行化操做,避免了併發問題,可是效率比較低。
後面能夠看一下mysql對隔離級別的實現。
索引的做用就和書的目錄相似,好比根據書名作索引,而後咱們經過書名就能夠直接翻到某一頁。數據表中咱們要找一條數據,也能夠根據它的主鍵來找到對應的那一頁。固然數據庫的搜索不是翻書,若是一頁一頁翻書,就至關因而全表掃描了,效率很低,因此人翻書確定也是跳着翻。數據庫也會基於相似的原理"跳着」翻書,快速地找到索引行。
MySQL是oracle公司的免費數據庫,做爲關係數據庫火了好久了。因此咱們要學他。
MySQL數據庫的架構能夠分爲客戶端,服務端,存儲引擎和文件系統。
詳細能夠看下架構圖,我稍微總結下
最高層的客戶端,經過tcp鏈接mysql的服務器,而後執行sql語句,其中涉及了查詢緩存,執行計劃處理和優化,接下來再到存儲引擎層執行查詢,底層實際上訪問的是主機的文件系統。
複製代碼
1 登陸mysql
mysql -h 127.0.0.1 -u 用戶名 -p
2 建立表 語法仍是比較複雜的,以前有騰訊面試官問這個,而後答不上來。
CREATE TABLE `user_accounts` (
`id` int(100) unsigned NOT NULL AUTO_INCREMENT primary key,
`password` varchar(32) NOT NULL DEFAULT '' COMMENT '用戶密碼',
`reset_password` tinyint(32) NOT NULL DEFAULT 0 COMMENT '用戶類型:0-不須要重置密碼;1-須要重置密碼',
`mobile` varchar(20) NOT NULL DEFAULT '' COMMENT '手機',
`create_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
`update_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
-- 建立惟一索引,不容許重複
UNIQUE INDEX idx_user_mobile(`mobile`)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8
複製代碼
3 crud比較簡單,不談
4 join用於多表鏈接,查詢的一般是兩個表的字段。
union用於組合同一種格式的多個select查詢。
6 聚合函數,通常和group by一塊兒使用,好比查找某部門員工的工資平均值。 就是select AVE(money) from departmentA group by department
7 創建索引
惟一索引(UNIQUE) 語法:ALTER TABLE 表名字 ADD UNIQUE (字段名字)
添加多列索引 語法:
ALTER TABLE table_name ADD INDEX index_name ( column1, column2, column3)
8 修改添加列
添加列 語法:alter table 表名 add 列名 列數據類型 [after 插入位置];
刪除列 語法:alter table 表名 drop 列名稱;
9 清空表數據 方法一:delete from 表名; 方法二:truncate from "表名";
DELETE:1. DML語言;2. 能夠回退;3. 能夠有條件的刪除;
TRUNCATE:1. DDL語言;2. 沒法回退;3. 默認全部的表內容都刪除;4. 刪除速度比delete快。
下面咱們討論的是innodb的存儲原理
innodb的存儲引擎將數據存儲單元分爲多層。按此不表
MySQL中的邏輯數據庫只是一個shchme。事實上物理數據庫只有一個。
mysql使用兩個文件分別存儲數據庫的元數據和數據庫的真正數據。
數據頁結構 頁是 InnoDB 存儲引擎管理數據的最小磁盤單位,而 B-Tree 節點就是實際存放表中數據的頁面,咱們在這裏將要介紹頁是如何組織和存儲記錄的;首先,一個 InnoDB 頁有如下七個部分:
每個頁中包含了兩對 header/trailer:內部的 Page Header/Page Directory 關心的是頁的狀態信息,而 Fil Header/Fil Trailer 關心的是記錄頁的頭信息。
也就是說,外部的h-t對用來和其餘頁造成聯繫,而內部的h-t用來是保存內部記錄的狀態。
複製代碼
User Records 就是整個頁面中真正用於存放行記錄的部分,而 Free Space 就是空餘空間了,它是一個鏈表的數據結構,爲了保證插入和刪除的效率,整個頁面並不會按照主鍵順序對全部記錄進行排序,它會自動從左側向右尋找空白節點進行插入,行記錄在物理存儲上並非按照順序的,它們之間的順序是由 next_record 這一指針控制的。
也就是說,一個頁中存了很是多行的數據,而每一行數據和相鄰行使用指針進行鏈表鏈接。
複製代碼
1 MySQL的innodb支持聚簇索引,myisam不支持聚簇索引。
innodb在建表時自動按照第一個非空字段或者主鍵創建聚簇索引。mysql使用B+樹創建索引。
每個非葉子結點只存儲主鍵值,而葉子節點則是一個數據頁,這個數據頁就是上面所說的存儲數據的page頁。
一個節點頁對應着多行數據,每一個節點按照順序使用指針連成一個鏈表。mysql使用索引訪問一行數據時,先經過log2n的時間訪問到葉子節點,而後在數據頁中按照行數鏈表執行順序查找,直到找到那一行數據。
2 b+樹索引能夠很好地支持範圍搜索,由於葉子節點經過指針相連。
explain主要用於檢查sql語句的執行計劃,而後分析sql是否使用到索引,是否進行了全局掃描等等。
mysql慢查詢日誌能夠在mysql的,my.cnf文件中配置開啓,而後執行操做超過設置時間就會記錄慢日誌。
好比分析一個sql:
explain查看執行計劃
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE vote_record \N ALL votenum,vote \N \N \N 996507 50.00 Using where
仍是沒用到索引,由於不符合最左前綴匹配。查詢須要3.5秒左右
最後修改一下sql語句
EXPLAIN SELECT * FROM vote_record WHERE id > 0 AND vote_num > 1000;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE vote_record \N range PRIMARY,votenum,vote PRIMARY 4 \N 498253 50.00 Using where
用到了索引,可是隻用到了主鍵索引。再修改一次
EXPLAIN SELECT * FROM vote_record WHERE id > 0 AND vote_num = 1000;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE vote_record \N index_merge PRIMARY,votenum,vote votenum,PRIMARY 8,4 \N 51 100.00 Using intersect(votenum,PRIMARY); Using where
用到了兩個索引,votenum,PRIMARY。
複製代碼
binlog就是二進制日誌,用於記錄用戶數據操做的日誌。用於主從複製。
redolog負責事務的重作,記錄事務中的每一步操做,記錄完再執行操做,而且在數據刷入磁盤前刷入磁盤,保證能夠重作成功。
undo日誌負責事務的回滾,記錄事務操做中的原值,記錄完再執行操做,在事務提交前刷入磁盤,保證能夠回滾成功。
這兩個日誌也是實現分佈式事務的基礎。
mysql通常提供多種數據類型,int,double,varchar,tinyint,datatime等等。文本的話有fulltext,mediumtext等。沒啥好說的。
sql能優化的點是在有點多。
好比基本的,不使用null判斷,不使用>< 分頁的時候利用到索引,查詢的時候注意順序。
若是是基於索引的優化,則要注意索引列是否可以使用到
1 索引列不要使用>< != 以及 null,還有exists等。
2 索引列不要使用匯集函數。
3 若是是聯合索引,排在第一位的索引必定要用到,不然後面的也會失效,爲何呢,由於第一列索引不一樣時纔會找第二列,若是沒有第一列索引,後續的索引頁沒有意義。
舉個例子。聯合索引A,B,C。查詢時必需要用到A,可是A的位置無所謂,只要用到就行,A,B,C或者C,B,A均可以。
4 分頁時直接limit n 5可能用不到索引,假設索引列是ID,那麼咱們使用where id > n limit 5就能夠實現上述操做了。
複製代碼
innodb支持行級鎖和事務,而myisam只支持表鎖,它的全部操做都須要加鎖。
1 鎖
鎖能夠分爲共享鎖和排它鎖,也叫讀鎖和寫鎖。
select操做默認不加鎖,須要加鎖時會用for update加排它鎖,或者用in share mode表示加共享鎖。
這裏的鎖都是行鎖。
innodb會使用行鎖配合mvcc一同完成事務的實現。
而且使用next-key lock來實現可重複讀,而沒必要加表鎖或者串行化執行。
複製代碼
2 MVCC
MVCC是多版本控制協議。
經過時間戳來判斷前後順序,而且是無鎖的。可是須要額外存一個字段。
讀操做比較本身的版本號,自動讀取比本身版本號新的版本。不讀。
寫操做自動覆蓋寫版本號比本身的版本號早的版本。不然不寫。
這樣保證必定程度上的一致性。
MVCC比較好地支持讀多寫少的情景。
可是偶爾須要加鎖時纔會進行加鎖。
複製代碼
3 事務
因此看看innodb如何實現事務的。
首先,innodb的行鎖是加在索引上的,由於innodb默認有聚簇索引,但實際上的行鎖是對整個索引節點進行加鎖,鎖了該節點全部的行。
看看innodb如何實現隔離級別以及解決一致問題
未提交讀,會致使髒讀,沒有併發措施
已提交讀,寫入時須要加鎖,使用行級寫鎖鎖加鎖指定行,其餘事務就看不到未提交事務的數據了。可是會致使不可重讀,
可重複讀:在原來基礎上,在讀取行時也須要加行級讀鎖,這樣其餘事務不能修改這些數據。就避免了不可重讀。
可是這樣會致使幻讀。
序列化:序列化會串行化讀寫操做來避免幻讀,事實上就是事務在讀取數據時加了表級讀鎖。
複製代碼
可是實際上。mysql的新版innodb引擎已經解決了幻讀的問題,而且使用的是可重複讀級別就能解決幻讀了。
實現的原理是next-key lock。是gap lock的增強版。不會鎖住全表,只會鎖住被讀取行先後的間隙行。
分庫分表的方案比較多,首先看下分表。
當一個大表沒辦法繼續優化的時候,可使用分表,橫向拆分的方案就是把一個表的數據放到多個表中。通常能夠按照某個鍵來分表。好比最經常使用的id,1-100w放在表一。100w-200w在表二,以此類推。
若是是縱向分表,則能夠按列拆分,好比用戶信息的字段放在一個表,用戶使用數據放在另外一個表,這其實就是一次性拆表了。
分庫的話就是把數據表存到多個庫中了,和橫向分表的效果差很少。
若是隻是單機的分表分庫,其性能瓶頸在於主機。
咱們須要考慮擴展性,因此須要使用分佈式的數據庫。
==分佈式數據庫解決方案mycat==
mycat是一款支持分庫分表的數據庫中間件,支持單機也支持分佈式。
首先部署mycat,mycat的訪問方式和一個mysqlserver是相似的。裏面能夠配置數據庫和數據表。
而後在mycat的配置文件中,咱們能夠指定分片,好比按照id分片,而後在每一個分片下配置mysql節點,能夠是本地的數據庫實例也能夠是其餘主機上的數據庫。
這樣的話,每一個分片都能找到對應機器上的數據庫和表了。
用戶鏈接mycat執行數據庫操做,實際上會根據id映射到對應的數據庫和表中,
複製代碼
主從複製大法好,爲了不單點mysql宕機和丟失數據,咱們通常使用主從部署,主節點將操做日誌寫入binlog,而後日誌文件經過一個鏈接傳給從節點的relaylog。從節點定時去relaylog讀取日誌,而且執行操做。這樣保證了主從的同步。
讀寫分離大法好,爲了不主庫的讀寫壓力太大,因爲業務以讀操做爲主,因此主節點通常做爲主庫,讀節點做爲從庫,從庫負責讀,主庫負責寫,寫入主庫的數據經過日誌同步給從庫。這樣的部署就是讀寫分離。
使用mycat中間件也能夠配置讀寫分離,只需在分片時指定某個主機是讀節點仍是寫節點便可。
分佈式關係數據庫無非就是關係數據庫的分佈式部署方案。
真正的分佈式數據庫應該是nosql數據庫,好比基於hdfs的hbase數據庫。底層就是分佈式的。
redis的分佈式部署方案也比較成熟。