C++後臺開發知識總結(二)數據庫

相關:
C++後臺開發知識總結(一)C++基礎
C++後臺開發知識總結(二)數據庫
C++後臺開發知識總結(三)計算機網絡
C++後臺開發知識總結(四)操作系統/Linux 內核

數據庫索引

索引是存儲引擎快速找到記錄的一種數據結構。
添加索引原則:
在查詢中很少使用或者參考的列不應該創建索引。
只有很少數據值的列也不應該增加索引。
定義爲text、image和bit數據類型的列不應該增加索引。
當修改性能遠遠大於檢索性能時,不應該創建索引。這是因爲,修改性能和檢索性能是互相矛盾的。

目前大部分數據庫系統及文件系統都採用B-Tree或其變種B+Tree作爲索引結構
B-Tree
B-Tree是一種平衡的多路查找(又稱排序)樹,在文件系統中和數據庫系統中有所應用。主要用作文件的索引。其中的B就表示平衡(Balance) 。
定義一條數據記錄爲一個二元組[key, data],key爲記錄的鍵值,對於不同數據記錄,key是互不相同的;data爲數據記錄除key外的數據。那麼B-Tree是滿足下列條件的數據結構:1.d>=2,即B-Tree的度;
2.h爲B-Tree的高;
3.每個非葉子結點由n-1個key和n個指針組成,其中d<=n<=2d;
4.每個葉子結點至少包含一個key和兩個指針,最多包含2d-1個key和2d個指針,葉結點的指針均爲NULL;
5.所有葉結點都在同一層,深度等於樹高h;
6.key和指針相互間隔,結點兩端是指針;
7.一個結點中的key從左至右非遞減排列;
8.如果某個指針在結點node最左邊且不爲null,則其指向結點的所有key小於v(key1),其中v(key1)爲node的第一個key的值。
9.如果某個指針在結點node最右邊且不爲null,則其指向結點的所有key大於v(keym),其中v(keym)爲node的最後一個key的值。
10.如果某個指針在結點node的左右相鄰key分別是keyi和keyi+1且不爲null,則其指向結點的所有key小於v(keyi+1)且大於v(keyi)。
一個d=2的B-Tree示意圖:
在這裏插入圖片描述
B-Tree是一個非常有效率的索引數據結構。這主要得益於B-Tree的度可以非常大,高度會變的非常小,只需要二分幾次就可以找到數據。例如一個度爲d的B-Tree,設其索引N個key,則其樹高h的上限爲logd((N+1)/2)),檢索一個key,其查找節點個數的漸進複雜度爲O(logdN)。
索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲的磁盤上。這樣的話,索引查找過程中就要產生磁盤I/O消耗。索引的結構組織要儘量減少查找過程中磁盤I/O的存取次數。
B+Tree的特性
區別於B-Tree:
每個節點的指針上限爲2d而不是2d+1
內節點不存儲data,只存儲key;葉子節點不存儲指針
帶有順序訪問指針的B+Tree

數據庫添加索引

1.普通索引:
僅加速查詢 最基本的索引,沒有任何限制,是大多數情況下使用到的索引。CREATE INDEX index_name on user_info(name)

#創建表的時候同時創建索引:

create table healerjean (
  id   bigint(20)  NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT  '主鍵',
  name  VARCHAR(32) NOT NULL COMMENT '姓名',
  email VARCHAR(64) NOT NULL COMMENT  '郵箱',
  message text DEFAULT  NULL COMMENT '個人信息',
  INDEX index_name (name) COMMENT '索引name'
) COMMENT  = '索引測試表';

#在存在的表上創建索引

create index index_name on healerjean(name)

#對於創建索引時如果是blob 和 text 類型,必須指定length。

create index ix_extra on in1(message(200));
alter table employee add index emp_name (name);

2.唯一索引:
與普通索引類型不同的是:加速查詢 + 列值唯一(可以有null)CREATE UNIQUE INDEX mail on user_info(name)
3.全文索引:
全文索引(FULLTEXT)僅可以適用於MyISAM引擎的數據表;作用於CHAR、VARCHAR、TEXT數據類型的列。
4.組合索引:
將幾個列作爲一條索引進行檢索,使用最左匹配原則。
create index ind_sales2_companyid_moneys on sales2(company_id,moneys)

想要查看錶有幾個字段設置了索引, show index from healerjean

MySQL索引實現

MyISAM索引實現
MyISAM引擎使用B+Tree作爲索引結構,葉結點的data域存放的是數據記錄的地址。
在這裏插入圖片描述
MyISAM中索引檢索的算法爲首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,則取出其data域的值,然後以data域的值爲地址,讀取相應數據記錄。MyISAM的索引方式也叫做“非聚集”的。
在MyISAM中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是唯一的,而輔助索引的key可以重複。
在這裏插入圖片描述
InnoDB索引實現
InnoDB的數據文件本身就是索引文件。MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。
在這裏插入圖片描述
葉結點包含了完整的數據記錄。這種索引叫做聚集索引。因爲InnoDB的數據文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則MySQL系統會自動選擇一個可以唯一標識數據記錄的列作爲主鍵,如果不存在這種列,則MySQL自動爲InnoDB表生成一個隱含字段作爲主鍵,這個字段長度爲6個字節,類型爲長整形。
InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。換句話說,InnoDB的所有輔助索引都引用主鍵作爲data域。
在這裏插入圖片描述

數據庫事務:底層如何實現事務

數據庫事務(Database Transaction) ,是指作爲單個邏輯工作單元執行的一系列操作,要麼完全地執行,要麼完全地不執行。
一個數據庫事務通常包含了一個序列的對數據庫的讀/寫操作。作用:
1.爲數據庫操作序列提供了一個從失敗中恢復到正常狀態的方法,同時提供了數據庫即使在異常狀態下仍能保持一致性的方法。
2.當多個應用程序在併發訪問數據庫時,可以在這些應用程序之間提供一個隔離方法,以防止彼此的操作互相干擾。
當事務被提交給了DBMS(數據庫管理系統),則DBMS(數據庫管理系統)需要確保該事務中的所有操作都成功完成且其結果被永久保存在數據庫中,如果事務中有的操作沒有成功完成,則事務中的所有操作都需要被回滾,回到事務執行前的狀態;同時,該事務對數據庫或者其他事務的執行無影響。
一個邏輯工作單元要成爲事務,必須滿足ACID(原子性、一致性、隔離性和持久性) 屬性。
原子性(Atomicity):
事務作爲一個整體被執行,事物的所有操作要不成功,要不失敗回滾而回滾可以通過日誌來實現,日誌記錄着事務所執行的修改操作,在回滾時反向執行這些修改操作。
一致性(Consistency):
數據庫在事務執行前後都保持一致性狀態,在一致性狀態下,所有事務對一個數據的讀取結果都是相同的。
隔離性(Isolation):
多個事務併發執行時,一個事務的執行不應影響其他事務的執行。
持久性(Durability):
一旦事務提交,則其所做的修改將會永遠保存到數據庫中。

數據庫事務隔離

同一時間,只允許一個事務請求同一數據,不同的事務之間彼此沒有任何干擾。比如A正在從一張銀行卡中取錢,在A取錢的過程結束前,B不能向這張卡轉賬。

MySQL 4 種隔離級別

未提交讀READ UNCOMMITTED:
一個事務在提交之前,對其他事務是可見的,即事務可以讀取未提交的數據。存在“髒讀”(讀到了髒數據)問題;
提交讀READ COMMITTED:
事務在提交之前,對其它事務是不可見的。存在“不可重複讀”(兩次查詢的得到的結果可能不同,即可能在查詢的間隙,有事務提交了修改)問題。解決了“髒讀”問題。
可重複讀REPEATABLE READ:
在同一事務中多次讀取的數據是一致的。解決了髒讀和不可重複讀問題,存在“幻讀”(在事務兩次查詢間隙,有其他事務又插入或刪除了新的記錄)。— MySQL默認隔離級別
可串行化SERIALIZABLE:
強制事務串行化執行。即一個事物一個事物挨個來執行,可以解決上述所有問題。

mysql的MVCC機制

MVCC是一種多版本併發控制機制,是MySQL的InnoDB存儲引擎實現隔離級別的一種具體方式,用於實現提交讀和可重複讀這兩種隔離級別。MVCC是通過保存數據在某個時間點的快照來實現該機制,其在每行記錄後面保存兩個隱藏的列,分別保存這個行的創建版本號和刪除版本號,然後Innodb的MVCC使用到的快照存儲在Undo日誌中,該日誌通過回滾指針把一個數據行所有快照連接起來。

SQL優化

在經常性的檢索列上,建立必要索引,以加快搜索速率,避免全表掃描(索引覆蓋掃描);
多次查詢同樣的數據,可以考慮緩存該組數據;
審視select * form tables, 你需要所有列數據嗎?
切分查詢(大查詢切分成爲小查詢,避免一次性鎖住大量數據)
分解關聯查詢(單表查詢,結果在應用程序中進行關聯,可以減少處理過程中的鎖爭用)
儘量先做單表查詢;

inner join和left join

left join(左聯接) 返回包括左表中的所有記錄和右表中聯結字段相等的記錄
right join(右聯接) 返回包括右表中的所有記錄和左表中聯結字段相等的記錄
inner join(等值連接) 只返回兩個表中聯結字段相等的行
表A、 B記錄如下:

aID aNum bID
1 a20050111 1 2006032401
2 a20050112 2 2006032402
3 a20050113 3 2006032403
4 a20050114 4 2006032404
5 a20050115 8 2006032408

sql語句如下:

select * from A
left join B 
on A.aID = B.bID

結果如下:

aID aNum bID
1 a20050111 1 2006032401
2 a20050112 2 2006032402
3 a20050113 3 2006032403
4 a20050114 4 2006032404
5 a20050115 NULL NULL

數據庫引擎innoDB與MyISAM

數據庫引擎是用於存儲、處理和保護數據的核心服務。在Mysql數據庫中,常用的引擎爲innoDB和MyISAM(MySQL5.6版本開始Innodb已經成爲Mysql的默認引擎,之前是MyISAM)。

數據庫引擎 innoDB與MyIASM區別:
1.InnoDB支持事務,支持外鍵,MyISAM都不支持;
2.InnoDB是聚集索引,數據文件是和索引綁在一起的,必須要有主鍵,通過主鍵索引效率很高。但是輔助索引需要兩次查詢,先查詢到主鍵,然後再通過主鍵查詢到數據。因此,主鍵不應該過大,因爲主鍵太大,其他索引也都會很大。
MyISAM是非聚集索引,數據文件是分離的,索引保存的是數據文件的指針。主鍵索引和輔助索引是獨立的;
3. 行數保存: InnoDB不保存表的具體行數,執行select count(*) from table時需要全表掃描。MyISAM用一個變量保存了整個表的行數,執行上述語句時只需要讀出該變量即可,速度很快;
4. Innodb不支持全文索引,MyISAM支持全文索引,查詢效率上MyISAM要高於Innodb;

如何選擇存儲引擎
如果在應用中執行大量select(查詢)操作,應該選MyIASM,如果在應用中執行大量的insert(插入)和update(更新)操作,應該選擇innoDB
如果要提供提交、回滾、崩潰恢復能力的事物安全(ACID兼容)能力,並要求實現併發控制,InnoDB是一個好的選擇

#查看數據庫支持的存儲引擎
show engines
#查看數據庫當前使用的存儲引擎,就是默認引擎是什麼。
show variables like 'storage_engine'
也可以在MySQL配置文件中查看。
windows - my.ini Linux - my.cnf
#查看數據庫表所用的存儲引擎
show create table table_name
#創建表指定存儲引擎
create table table_name (column_name column_type) engine = engine_name
#修改表的存儲引擎
alter table table_name engine=engine_name
#修改默認的存儲引擎
在MySQL配置文件中修改下述內容:default-storage-engine=INNODB
MySQL的端口號是多少,如何修改這個端口號
查看端口號:
登錄mysql: mysql -u root –p
查看端口號: show global variables like 'port'
mysql的默認端口是3306。(補充:sqlserver默認端口號爲:1433;oracle默認端口號爲:1521;DB2默認端口號爲:5000;PostgreSQL默認端口號爲:5432)
修改端口號:編輯/etc/my.cnf文件,早期版本有可能是my.conf文件名,增加端口參數,並且設定端口,注意該端口未被使用,保存退出。重啓mysql。

存儲過程

存儲過程簡單來說,就是爲以後的使用而保存的一條或多條MySQL語句的集合。
目的:把處理封裝,簡化複雜的操作;所有開發人員和應用程序都使用同一存儲過程,防止錯誤保證了數據的一致性;簡化對變動的管理,只需要更改存儲過程的代碼。

#創建存儲過程

create procedure porcedureName () 
begin 
    select name from user; 
end;  

#調用存儲過程:

call procedureName ();  

#刪除存儲過程

DROP PROCEDURE IF EXISTS porcedureName; 

#含參數

create procedure getTotalById ( 
    in userId int, 
    out total decimal(8,2) 
) 
BEGIN 
    select SUM(r.price) from order r 
    where r.u_id = userId 
    into total; 
END; 

調用

call getTotalById(1, @total); 
select @total;  

數據庫的第一二三範式

第一範式(1NF)
數據庫表的每一列都是不可分割的原子數據項,而不能是集合,數組,記錄等非原子數據項。
通俗講就是:一個字段只存儲一項信息。
第二範式
如果關係模式R滿足第一範式,並且R得所有非主屬性都完全依賴於R的每一個候選關鍵屬性,稱R滿足第二範式(屬性完全依賴於每一個主鍵)。滿足第一範式前提,當一個主鍵由多個屬性共同組成時,纔會發生不符合第二範式的情況。比如有兩個屬性的主鍵,不能存在這樣的屬性,它只依賴於主鍵中的一個屬性,這就是不符合第二範式 。
非主鍵列是否完全依賴於主鍵,還是依賴於主鍵的一部分?
第三範式
定義:第三範式(屬性不能傳遞依賴於主屬性)。滿足第二範式前提,如果某一屬性依賴於其他非主鍵屬性,而其他非主鍵屬性又依賴於主鍵,那麼這個屬性就是間接依賴於主鍵,這被稱作傳遞依賴於主屬性。
非主鍵列是直接依賴於主鍵,還是直接依賴於非主鍵列?

delete、truncate、drop的區別及應用場所

1、delete屬於DML(數據庫操作語言),DELETE語句執行刪除的過程是每次從表中刪除一行,並且同時將該行的刪除操作作爲事務記錄在日誌中保存以便進行進行回滾操作,truncate、drop屬於DDL(數據庫定義語言),不能回滾
2、在速度上,一般來說,drop> truncate > delete
3、TRUNCATE 和DELETE只刪除數據, DROP則刪除整個表(結構和數據)
4、Truncate table 表名 速度快,而且效率高,因爲: truncate table 在功能上與不帶 WHERE 子句的 DELETE 語句相同:二者均刪除表中的全部行。但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系統和事務日誌資源少。DELETE 語句每次刪除一行,並在事務日誌中爲所刪除的每行記錄一項。TRUNCATE TABLE 通過釋放存儲表數據所用的數據頁來刪除數據,並且只在事務日誌中記錄頁的釋放。
實例:刪除學生表
1、當你不再需要該表時, 用 drop;
2、當你仍要保留該表,但要刪除所有記錄時, 用 truncate;
3、當你要刪除部分記錄時, 用 delete。
drop table table_name : 刪除表全部數據和表結構,立刻釋放磁盤空間,不管是 Innodb 和 MyISAM;
truncate table table_name : 刪除表全部數據,保留表結構,立刻釋放磁盤空間 ,不管是 Innodb 和 MyISAM;
delete from table_name :刪除表全部數據,表結構不變,對於 MyISAM 會立刻釋放磁盤空間,InnoDB 不會釋放磁盤空間;
delete from table_name where xxx : 帶條件的刪除,表結構不變,不管是 innodb 還是 MyISAM 都不會釋放磁盤空間;
delete 操作以後,使用 optimize table table_name 會立刻釋放磁盤空間,不管是 innodb 還是 myisam;

DELETE FROM users WHERE name = ‘Mike’ ORDER BY id DESC LIMIT 6;

Redis數據類型

Redis通常被稱爲數據結構服務器
Redis支持五種數據類型:
1)String: 字符串:整數值、embstr編碼的簡單動態字符串、簡單動態字符串(SDS)
2)List: 列表:壓縮列表、雙端鏈表
3)Hash: 哈希:壓縮列表、字典
4)Set: 集合:整數集合、字典
5)Sorted Set: 有序集合:壓縮列表、跳躍表和字典

mongodb和redis的區別

內存管理機制上: Redis 數據全部存在內存,定期寫入磁盤,當內存不夠時,可以選擇指定的 LRU 算法刪除數據。MongoDB 數據存在內存,由 linux系統 mmap 實現,當內存不夠時,只將熱點數據放入內存,其他數據存在磁盤。
支持的數據結構上: Redis 支持的數據結構豐富,包括hash、set、list等。
MongoDB 數據結構比較單一,但是支持豐富的數據表達,索引,最類似關係型數據庫,支持的查詢語言非常豐富

Redis是單線程的,但是爲什麼這麼高效呢?

I/O多路複用監聽多個套接字
完全基於內存,內存操作快速
單進程單線程不用考慮切換/鎖的問題

單進程多線程模型:MySQL、Memcached、Oracle(win)
多進程模型:Oracle(Linux)

Redis的rehash怎麼做的,爲什麼要漸進rehash,漸進rehash又是怎麼實現的?

因爲redis是單線程,當K很多時,如果一次性將鍵值對全部rehash,龐大的計算量會影響服務器性能,甚至可能會導致服務器在一段時間內停止服務。不可能一步完成整個rehash操作,所以redis是分多次、漸進式的rehash。漸進性哈希分爲兩種:
1)操作redis時,額外做一步rehash
對redis做讀取、插入、刪除等操作時,會把位於table[dict->rehashidx]位置的鏈表移動到新的dictht中,然後把rehashidx做加一操作,移動到後面一個槽位。
2)後臺定時任務調用rehash
後臺定時任務rehash調用鏈,同時可以通過server.hz控制rehash調用頻率

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