【數據庫】基礎

1.union 和union all的區別

  • union會對結果集進行處理排除掉相同的結果
  • union all 不會對結果集進行處理,不會處理掉相同的結果

2.preparedStatement和statement的區別

  • 任何時候使用preparedStatement而不是statement
  • PreparedStatement預編譯,防止SQL注入
  • PreparedStatement多次使用可提高效率

3.數據庫三範式

  • 第一範式(1NF)無重複的列(原子性),每一列都是不可分割的原子數據項,而不能是集合,數組,記錄等非原子數據項。
  • 第二範式(2NF)屬性完全依賴於主鍵,如果有哪些數據只和主鍵的一部份有關的話,它就不符合第二範式。
  • 第三範式(3NF)屬性不依賴於其它非主屬性,每個非關鍵字列都獨立於其他非關鍵字列。

4.Mysql行級鎖

MYISAM引擎只支持表級鎖,而INNODB引擎能夠支持行級鎖,下面的內容也是針對INNODB行級鎖展開的:

⑴ 共享鎖

又稱讀鎖,是讀取操作創建的鎖。其他用戶可以併發讀取數據,但任何事務都不能對數據進行修改。
如果事務T對數據A加上共享鎖後,則其他事務只能對A再加共享鎖,不能加排它鎖。

SELECT ... LOCK IN SHARE MODE;

會對查詢出的每一條數據加共享鎖,如果其它線程再加排它鎖就會阻塞。

⑵ 排它鎖

又稱寫鎖,如果事務T對數據A加上排他鎖後,則其他事務不能再對A加任任何類型的鎖。獲准排他鎖的事務既能讀數據,又能修改數據。

SELECT ... FOR UPDATE;

在查詢語句後面增加FOR UPDATE,Mysql會對查詢結果中的每行都加排他鎖,當沒有其他線程對查詢結果集中的任何一行使用排他鎖時,可以成功申請排他鎖,否則會被阻塞。
另外mysql的innodb對數據的update,delete,insert都會給涉及到的數據加上排他鎖,select語句默認不會加任何鎖類型。所以加上排它鎖普通的select還是可以用的。

5.事務的基本要素(ACID特性)

  • 原子性(Atomicity):事務開始後所有操作,要麼全部做完,要麼全部不做,不可能停滯在中間環節。事務執行過程中出錯,會回滾到事務開始前的狀態,所有的操作就像沒有發生一樣。也就是說事務是一個不可分割的整體,就像化學中學過的原子,是物質構成的基本單位。
  • 一致性(Consistency):事務開始前和結束後,數據庫的完整性約束沒有被破壞 。比如A向B轉賬,不可能A扣了錢,B卻沒收到。
  • 隔離性(Isolation):同一時間,只允許一個事務請求同一數據,不同的事務之間彼此沒有任何干擾。比如A正在從一張銀行卡中取錢,在A取錢的過程結束前,B不能向這張卡轉賬。
  • 持久性(Durability):事務完成後,事務對數據庫的所有更新將被保存到數據庫,不能回滾。

6.事務的併發問題

  • 髒讀 對於兩個事務T1 和T2 , T1 讀取了已經被T2 更新但還沒有被提交的字段。之後,若T2 進行回滾,T1讀取的內容就是臨時且無效的
  • 不可重複讀 是指在一個事務中兩次讀同一行數據,可是這兩次讀到的數據不一樣
  • 幻讀 系統管理員A將數據庫中所有學生的成績從具體分數改爲ABCDE等級,但是系統管理員B就在這個時候插入了一條具體分數的記錄,當系統管理員A改結束後發現還有一條記錄沒有改過來,就好像發生了幻覺一樣,這就叫幻讀。

7.事務的隔離級別

  • 讀未提交(Read Uncommitted)事務A讀到事務B未提交的事務,就可能出現髒讀
  • 讀已提交(Read Committed)事務A只能讀到B已提交的事務(ORACLE等默認),
  • 可重複讀取(Repeatable Read)在同一個事務內的查詢都是事務開始時刻一致的,事務A讀則事務B就不能修改,可能出現幻讀,但是MySQL的innodb通過MVCC(多版本併發控制)解決了幻讀問題。
  • 序列化(Serializable) 事務串行化執行,你讀的時候別人都看不到

8.數據庫查詢語言分類

⑴DQL(Data Query Language)

數據查詢語言DQL由SELECT子句,FROM子句,WHERE子句組成

⑵DML(Data Manipulation Language)

數據操縱語言DML包含INSERT,UPDATE,DELETE

⑶DDL(Data Definition Language)

數據定義語言DDL用來創建數據庫中的各種對象-----表、視圖、
索引、同義詞、聚簇等如:
CREATE TABLE/VIEW/INDEX/SYN/CLUSTER
DDL操作是隱性提交的!不能rollback

⑷DCL(Data Control Language)

數據控制語言(DCL)是用來設置或者更改數據庫用戶或角色權限的語句,這些語句包括GRANT、DENY、REVOKE等語句,在默認狀態下,只有sysadmin、dbcreator、db_owner或db_securityadmin等角色的成員纔有權利執行數據控制語言。

9.mysql導出表結構

 sudo mysqldump -h10.1.210.15 -u用戶名 -p密碼 數據庫名 device_bind_info>device_bind_info.sql
 格式:
 sudo mysqldump -h地址 -u用戶名 -p密碼 數據庫名 表名>導出sql

10.樂觀鎖和悲觀鎖

  • 每次去拿數據的時候都認爲別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制。樂觀鎖適用於多讀的應用類型,這樣可以提高吞吐量,像數據庫如果提供類似於write_condition機制的其實都是提供的樂觀鎖。
  • 悲觀鎖每次去拿數據的時候都認爲別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。傳統的關係型數據庫裏邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。
  • 兩種鎖各有優缺點,不可認爲一種好於另一種,像樂觀鎖適用於寫比較少的情況下,即衝突真的很少發生的時候,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。但如果經常產生衝突,上層應用會不斷的進行retry,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適。

11.drop、truncate和delete的區別

  • 執行速度 drop > truncate > delete
  • delete一行一行刪除,truncate 刪除表全部數據,drop 連表數據和表結構一起刪除
  • delete 是 DML 語句,沒提交事務還可以回滾,truncate 和 drop 是 DDL 語句,操作完馬上生效,不能回滾
  • 有FOREIGN KEY 約束引用的表,不能使用 TRUNCATE TABLE,而應使用不帶 WHERE 子句的 DELETE 語句
  • delete刪除行會出現id不聯繫,truncate是id重新開始

12.水平分區和垂直分區和讀寫分離

  • 水平分區(Horizontal Partitioning) 這種形式分區是對錶的行進行分區,通過這樣的方式不同分組裏面的物理列分割的數據集得以組合,從而進行個體分割(單分區)或集體分割(1個或多個分區)。所有在表中定義的列在每個數據集中都能找到,所以表的特性依然得以保持。
    舉個簡單例子:一個包含十年發票記錄的表可以被分區爲十個不同的分區,每個分區包含的是其中一年的記錄。(注:這裏具體使用的分區方式我們後面再說,可以先說一點,一定要通過某個屬性列來分割,譬如這裏使用的列就是年份)
  • 垂直分區(Vertical Partitioning) 這種分區方式一般來說是通過對錶的垂直劃分來減少目標表的寬度,使某些特定的列被劃分到特定的分區,每個分區都包含了其中的列所對應的行。
    舉個簡單例子:一個包含了大text和BLOB列的表,這些text和BLOB列又不經常被訪問,這時候就要把這些不經常使用的text和BLOB了劃分到另一個分區,在保證它們數據相關性的同時還能提高訪問速度。
  • 讀寫分離,基本的原理是讓主數據庫處理事務性增、改、刪操作(INSERT、UPDATE、DELETE),而從數據庫處理SELECT查詢操作。數據庫複製被用來把事務性操作導致的變更同步到集羣中的從數據庫。

13.Mysql執行計劃

MySql提供了EXPLAIN語法用來進行查詢分析

| id | select_type | table  | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra       |
⑴id

查詢的序列號

⑵select_type
  • ⑴SIMPLE:簡單的select查詢,查詢中不包含子查詢或者union
  • ⑵PRIMARY:查詢中包含任何複雜的子部分,最外層查詢則被標記爲primary
  • ⑶SUBQUERY:在select 或 where列表中包含了子查詢
  • ⑷DERIVED:在from列表中包含的子查詢被標記爲derived(衍生),mysql或遞歸執行這些子查詢,把結果放在零時表裏
  • ⑸UNION:若第二個select出現在union之後,則被標記爲union;若union包含在from子句的子查詢中,外層select將被標記爲derived
  • ⑹UNION RESULT:從union表獲取結果的select
⑶table

輸出行所引用的表

⑷type(重要)

訪問類型,非常滴重要,結果從好到壞依次是:
system > const > eq_ref > ref(優秀線) > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range(合格線) > index > ALL

  • system:表中僅有一行(=系統表)這是const聯結類型的一個特例。
  • const:表示通過索引一次就找到,const用於比較primary key或者unique索引。因爲只匹配一行數據,所以如果將主鍵置於where列表中,mysql能將該查詢轉換爲一個常量
  • eq_ref:唯一性索引掃描,對於每個索引鍵,表中只有一條記錄與之匹配。常見於唯一索引或者主鍵掃描
  • ref:非唯一性索引掃描,返回匹配某個單獨值的所有行,本質上也是一種索引訪問,它返回所有匹配某個單獨值的行,可能會找多個符合條件的行,屬於查找和掃描的混合體
  • range:只檢索給定範圍的行,使用一個索引來選擇行。key列顯示使用了哪個索引,一般就是where語句中出現了between,in等範圍的查詢。這種範圍掃描索引掃描比全表掃描要好,因爲它開始於索引的某一個點,而結束另一個點,不用全表掃描
  • index:index 與all區別爲index類型只遍歷索引樹。通常比all快,因爲索引文件比數據文件小很多。
  • all:遍歷全表以找到匹配的行
⑸possible_keys

查詢涉及到的字段上存在索引,則該索引將被列出,但不一定被查詢實際使用,可能有多個

⑹key(重要)

實際使用的索引,如果爲NULL,則沒有使用索引,主要看這個而不是possible_keys,只能由一個

⑺key_len

MYSQL使用的索引長度

⑻ref

ref列顯示使用哪個列或常數與key一起從表中選擇行

⑼rows(重要)

顯示MYSQL執行查詢的行數,數值越大越不好,說明沒有用好索引

⑽filtered

存儲引擎返回的數據在server層過濾後,剩下多少滿足查詢的記錄數量的比例(百分比),值越大越好,filtered列的值依賴統計信息,並不十分準確

⑾Extra(重要)
①Using temporary

使用臨時表保存中間結果,也就是說mysql在對查詢結果排序時使用了臨時表,常見於order by 和 group by

②Using where

使用了where過濾
等等還有很多。。。

14.Mysql存儲引擎

查看存儲引擎:show engines;
有MyISAM,InnoDB,MEMORY,MERGE等,這裏只說MyISAM和InnoDB

⑴MyISAM
  • 如果表中絕大多數都只是讀查詢,可以考慮MyISAM,
  • 不支持事務
  • 不支持外鍵
  • 支持全文索引
⑵InnoDB
  • 適合更新請求密集的表
  • 支持事務
  • 自動從災難恢復
  • 外檢支持
  • 支持自動增加列AUTO_INCREMENT屬性
⑶兩者的區別
  • InnoDB支持事務,MyISAM不支持
  • InnoDB支持外鍵,MyISAM不支持
  • InnoDB支持行鎖,會死鎖,併發性能好,MyISAM僅支持表鎖,不會死鎖,併發性能差
  • InnoDB必須有主鍵,沒有指定就爲每一行數據生成不可見的ROWID列作爲主鍵,MyISAM可以沒有主鍵
  • InnoDB不支持全文索引,MyISAM支持,5.6開始InnoDB也支持全文索引了
  • MyISAM內置了一個計數器來存儲表的行數。執行 select count(*) 時直接從計數器中讀取,速度非常快。而InnoDB不保存這些信息
  • InnoDB所有的表都保存在同一個數據文件中(也可能是多個文件,或者是獨立的表空間文件),MyISAM將索引和數據分開進行存儲。
  • 對AUTO_INCREMENT的處理方式不一樣。如果將某個字段設置爲INCREMENT,InnoDB中規定必須包含只有該字段的索引。但是在MyISAM中,也可以將該字段和其他字段一起建立聯合索引。
  • delete from table的處理方式不一樣。MyISAM會重新建立表。InnoDB不會重新建立表,而是一行一行的刪除。
  • 如果執行大量的SELECT,MyISAM是更好的選擇。如果你的數據執行大量的INSERT或UPDATE,出於性能方面的考慮,應該使用InnoDB表

15.Mysql索引原理

MyISAM和InnoDB均採用b+樹的索引結構,但是具體實現還是有區別,這裏是innoDB的:
關於b+樹的數據結構可以看這裏:數據結構
在這裏插入圖片描述
爲什麼用b+樹呢:

  • b樹查找不穩定,b+樹因爲都在葉子節點所以穩定
  • 相同數據量的情況下,b+樹比b樹更矮胖,因此查詢io也要少,真實場景一般高度爲3
  • b+樹葉子節點有鏈表,所以範圍查詢更簡單

聚集索引和非聚集索引在索引原理的不同

  • 聚集索引索引和數據是一體的
  • 非聚集索引就是指B+Tree的葉子節點上的data,並不是數據本身,而是數據存放的地址
  • 非聚集索引比聚簇索引多了一次讀取數據的IO操作,所以查找性能上會差

16.索引分類

⑴從實現上說分爲聚集索引和非聚集索引
  • 正文內容按照一個特定維度排序存儲,這個特定的維度就是聚集索引,表中只能由一個,一般是表中的主鍵索引,如果表中沒有顯示指定主鍵,則會選擇表中的第一個不允許爲NULL的唯一索引,如果還是沒有的話,就採用Innodb存儲引擎爲每行數據內置的6字節ROWID作爲聚集索引。聚集索引性能在精確查找和範圍查找上面效果要好
  • 非聚集索引索引項順序存儲,但索引項對應的內容卻是隨機存儲的
⑵從功能上說分爲下面幾種
  • 普通索引:最基本的索引,沒有任何約束
  • 唯一索引:與普通索引類似,但具有唯一性約束,唯一索引數據列不能重複,可以提高效率,也可以防重
  • 主鍵索引:特殊的唯一索引,不允許有空值
  • 複合索引:將多個列組合在一起創建索引,可以覆蓋多個列
  • 外鍵索引:只有InnoDB類型的表纔可以使用外鍵索引,保證數據的一致性、完整性和實現級聯操作
  • 全文索引:MySQL 自帶的全文索引只能用於 InnoDB、MyISAM ,並且5.7之前只能對英文進行全文檢索,5.7之後開始支持中文
⑶從結構上分
  • Btree(其實就是b+樹)
  • Hash索引(基本不用)

17.索引用法

⑴什麼地方使用索引
  • 經常搜索的列
  • 主鍵列
  • 連接列
  • 範圍搜索列,因爲索引進行了排序
  • where子句列
⑵索引注意事項
  • 查詢很少的列不創建索引
  • 列值較少(性別)的列不創建索引
  • image,bit數據類型的列不創建索引
  • 修改性能遠遠大於索引性能的列,索引會提高檢索性能但會降低修改性能。
  • 只要列中包含有NULL值都將不會被包含在索引中,所以我們在數據庫設計時不要讓字段的默認值爲NULL。
  • 對字符串列進行索引,如果可能應該指定一個前綴長度。例如,如果有一個CHAR(255)的列,如果在前10個或20個字符內,多數值是惟一的,那麼就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁盤空間和I/O操作。
  • like “%aaa%” 不會使用索引而like “aaa%”可以使用索引,以%開頭不會利用到索引,結尾可以。
  • 不要在索引列上進行運算,我們可以吧 id - 2 = 1改成id = 1 + 2 的形式
  • 不使用NOT IN和<>操作
  • 符合最左前綴原則
⑶最左前綴的理解
①舉例

基於版本號5.7,我們建立索引(aa, bb, cc),默認創建出來的都是BTREE結構
首先我們創建數據庫:

CREATE TABLE `bincai` (
	`id` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
	`aa` VARCHAR(15) DEFAULT '',
	`bb` VARCHAR(15) DEFAULT '',
	`cc` VARCHAR(15) DEFAULT '',
	`dd` VARCHAR(15) DEFAULT '',
	PRIMARY KEY (`id`),
	KEY `heidou` (`aa`, `bb`, `cc`)
) ENGINE = InnoDB CHARSET = utf8;

然後再往表裏插入幾條數據

insert into bincai(aa,bb,cc,dd) values('11','12','13','14');
insert into bincai(aa,bb,cc,dd) values('21','22','23','24');
insert into bincai(aa,bb,cc,dd) values('31','32','33','34');

例子1:

explain select * from bincai where bb = '12';

輸出:

| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | bincai | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |    33.33 | Using where |

例子2(覆蓋索引):

explain select bb from bincai where bb = '12';

輸出:

| id | select_type | table  | partitions | type  | possible_keys | key    | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+--------+------------+-------+---------------+--------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | bincai | NULL       | index | NULL          | heidou | 144     | NULL |    3 |    33.33 | Using where; Using index |

在第二個查詢中並不符合最左前綴倒是也利用到了索引,這是爲啥呢?
因爲查詢的字段是索引字段,所以採用了覆蓋索引(Extra裏面有Using index),所以無論條件是否滿足最左都會使用索引,但是注意type是index,而且rows是3,mysql會一條條查找數據,效率其實不高。另外要注意查詢的字段一定要在同一個聯合索引裏纔會產生覆蓋索引
例子3:

explain select aa,bb,dd from bincai where aa = '12';

輸出:

| id | select_type | table  | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+--------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | bincai | NULL       | ref  | heidou        | heidou | 48      | const |    1 |   100.00 | NULL  |

當我們完全符合最左前綴原則時,rows是1,type是ref,這纔是索引的正確姿勢,這時候即使我們查索引覆蓋的字段:

explain select aa,bb from bincai where aa = '12';

輸出:

| id | select_type | table  | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra       |
+----+-------------+--------+------------+------+---------------+--------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | bincai | NULL       | ref  | heidou        | heidou | 48      | const |    1 |   100.00 | Using index |

例子4:

explain select * from bincai where cc = '12' and aa ='12';

輸出:

| id | select_type | table  | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra                 |
+----+-------------+--------+------------+------+---------------+--------+---------+-------+------+----------+-----------------------+
|  1 | SIMPLE      | bincai | NULL       | ref  | heidou        | heidou | 48      | const |    1 |    33.33 | Using index condition |

我們發現也使用到了heidou的索引。這是因爲mysql有查詢優化器,會將cc = ‘12’ and aa ='12’糾正順序,生成真正的執行計劃,從而利用到索引。

②總結
  • 查詢的字段在同一個聯合索引裏,如果where後面不符合索引規則,會產生覆蓋索引
  • sql查詢優化器會幫我們優化順序,只需要聯合索引第一個在where後面就行

18.覆蓋索引

如果一個索引包含(或覆蓋)所有需要查詢的字段的值,稱爲‘覆蓋索引’。即只需掃描索引而無須回表。

  • 覆蓋索引必須要存儲索引的列,所以只能用Btree索引做覆蓋索引
  • 當發起一個索引覆蓋查詢時,在explain的extra列可以看到using index的信息

19.in與not in,exists與not exists的區別

  • exist會針對子查詢的表使用索引
  • not exist會對主子查詢都會使用索引
  • in與子查詢一起使用的時候,只針對主查詢使用索引
  • not in則不會使用任何索引
  • 如果查詢的兩個表大小相當,那麼用in和exists差別不大;如果兩個表中一個較小一個較大,則子查詢表大的用exists,子查詢表小的用in
  • 所以無論哪個表大,用not exists都比not in 要快

exists案例解析:

SELECT
 A.*
FROM
 A
WHERE
EXISTS (SELECT B.* FROM B WHEN A.id = B.id)

首先執行

SELECT A.* FROM  A

然後將其結果集作爲條件,在where中進行篩選,exists篩選結果集爲true的數據項,而not exists相反,返回結果集爲false的數據項

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