數(shù)據(jù)庫的三范式 第一范式:1NF是對屬性的原子性約束,,要求屬性具有原子性,,不可再分解; 第二范式:2NF是對記錄的惟一性約束,要求記錄有惟一標識,,即實體的惟一性,; 第三范式:3NF是對字段冗余性的約束,即任何字段不能由其他字段派生出來,它要求字段沒有冗余,。 SQL執(zhí)行順序 關(guān)鍵字:select,、from,、join、on、where,、group by,、having,、order by、distinct執(zhí)行順序 from > join > on > where > group by > having > select > distinct > order by UNION/ALL,、EXCEPT/ALL和INTERSECT/ALL UNION/ALL:組合多個結(jié)果表,并消去表中重復(fù)行,,和ALL一起使用時,,不消除重復(fù)行。 EXCEPT/ALL:在table1中但不在table2中的行并消除重復(fù)行,,和ALL一起使用時,,不消除重復(fù)行。 INTERSECT/ALL:包括table1和table2中都有的行并消除重復(fù)行,,和ALL一起使用時,,不消除重復(fù)行。 內(nèi)連接,、外連接,、笛卡兒積(交叉連接) 內(nèi)連接:結(jié)果僅包含符合連接條件的兩表中的行 外連接:結(jié)果包含符合條件的行,同時包含不符合條件的行(分為左外連接,、右外連接和全外連接) 左外連接:左表全部行+右表匹配的行,,如果左表中某行在右表中沒有匹配的行,則顯示NULL,。 右外連接:右表全部行+左表匹配的行,。 全外連接:全外連接:不管匹配不匹配,全部顯示出來,。 交叉連接:返回左表中所有行與右表中所有行的組合,,也稱笛卡爾積。 VARCHAE和CHAR的區(qū)別 CHAR:指定長度,,如果一個數(shù)據(jù)實際長度比設(shè)定長度短,,那么它將按照設(shè)定(最長)長度儲存,不足部分,,填補空格,。適用于固定長度的字段,如性別,、手機號等,。 VARCHAE:指定最大長度,但該長度可變,,即如果數(shù)據(jù)的實際長度比設(shè)定長度短,,那么它將按照實際長度儲存,而不占用剩余的空間。 適用于非固定長度的字段,,如姓名,、城市名等。 DROP,,DELETE與TRUNCATE的區(qū)別 DROP直接刪掉表 ,。 TRUNCATE刪除表中數(shù)據(jù),再插入時自增長id又從1開始 ,。 DELETE刪除表中數(shù)據(jù),,可以加WHERE字句。 數(shù)據(jù)庫事務(wù)(ACID) 原子性(Atomicity)一個事務(wù)必須被視為一個不可分割的最小工作單元,,整個事務(wù)中的所有操作要么全部提交成功,要么全部失敗回滾,,對于一個事務(wù)來說,,不可能只執(zhí)行其中的一部分操作。 一致性(Consistency)數(shù)據(jù)庫總是從一個一致性的狀態(tài)轉(zhuǎn)換到另一個一致性的狀態(tài),。 隔離性(Isolation)一個事務(wù)所做的修改在最終提交以前,,對其他事務(wù)是不可見的。 持久性(Durability)一旦事務(wù)提交,,則其所做的修改不會永久保存到數(shù)據(jù)庫,。 數(shù)據(jù)庫的樂觀鎖和悲觀鎖 悲觀鎖:對數(shù)據(jù)被外界修改持保守態(tài)度,因此,,在整個數(shù)據(jù)處理過程中,,將數(shù)據(jù)處于鎖定狀態(tài)。(悲觀鎖的實現(xiàn),,往往依靠數(shù)據(jù)庫提供的鎖機制) 樂觀鎖:大多是基于數(shù)據(jù)版本 ( Version )記錄機制實現(xiàn),。 即為數(shù)據(jù)增加一個版本標識,在基于數(shù)據(jù)庫表的版本解決方案中,,一般是通過為數(shù)據(jù)庫表增加一個 “version” 字段來 實現(xiàn),。 讀取出數(shù)據(jù)時,將此版本號一同讀出,,之后更新時,,對此版本號加一。此時,,將提 交數(shù)據(jù)的版本數(shù)據(jù)與數(shù)據(jù)庫表對應(yīng)記錄的當前版本信息進行比對,,如果提交的數(shù)據(jù) 版本號大于數(shù)據(jù)庫表當前版本號,則予以更新,,否則認為是過期數(shù)據(jù) 臟讀,、虛讀和不可重復(fù)讀 臟讀:一個事務(wù)讀取到了另外一個事務(wù)沒有提交的數(shù)據(jù);(修改的數(shù)據(jù)還未提交就被另一個事務(wù)使用這個數(shù)據(jù)) 不可重復(fù)讀:在同一事務(wù)中,兩次讀取同一數(shù)據(jù),,得到內(nèi)容不同,;(兩次讀取同一數(shù)據(jù)之間,另一個事務(wù)對數(shù)據(jù)進行了修改) 虛度:同一事務(wù)中,,用同樣的操作讀取兩次,,得到的記錄數(shù)不相同;(兩次相同的操作之間,,另一個事務(wù)對數(shù)據(jù)進行了新增或刪除) MySQL中的四種事務(wù)隔離級別 序列化 (Serializable):可避免臟讀,、不可重復(fù)讀、幻讀的發(fā)生,。 可重復(fù)讀 (Repeatable read):可避免臟讀,、不可重復(fù)讀的發(fā)生。 讀已提交(Read committed):可避免臟讀的發(fā)生,。 讀未提交 (Read uncommitted):最低級別,,任何情況都無法保證。 MVCC(多版本并發(fā)控制) MVCC最大的好處:讀不加鎖,,讀寫不沖突,。 1.多版本并發(fā)控制(MVCC)是一種用來解決讀-寫沖突的無鎖并發(fā)控制,也就是為事務(wù)分配單向增長的時間戳,,為每個修改保存一個版本,,版本與事務(wù)時間戳關(guān)聯(lián),讀操作只讀該事務(wù)開始前的數(shù)據(jù)庫的快照,。 這樣在讀操作不用阻塞寫操作,,寫操作不用阻塞讀操作的同時,避免了臟讀和不可重復(fù)讀 2.當MVCC數(shù)據(jù)庫更新一條數(shù)據(jù)時,,不會直接重寫原始的數(shù)據(jù),,而是修改新創(chuàng)建的數(shù)據(jù)副本。因此會有多個版本的數(shù)據(jù)被保存下來,。每個事務(wù)看到的數(shù)據(jù)版本依賴于隔離級別的實現(xiàn),。MVCC里最通用的隔離級別的實現(xiàn)就是快照隔離。在快照隔離的情況下,,事務(wù)只會獲取到數(shù)據(jù)的在事務(wù)開始前的狀態(tài),。 MYSQL主從復(fù)制 概念解釋 MySQL的Replication(英文為復(fù)制)是一個多MySQL數(shù)據(jù)庫做主從同步的方案,特點是異步復(fù)制,。 MySQL Replication 就是從服務(wù)器拉取主服務(wù)器上的二進制日志文件,,然后再將日志文件解析成相應(yīng)的SQL語句在從服務(wù)器上重新執(zhí)行一遍主服務(wù)器的操作,通過這種方式來保證數(shù)據(jù)的一致性,。主從復(fù)制原理 1.master(主)在執(zhí)行sql之后,,記錄二進制log文件(bin-log),。 2.slave(從)連接master,并從master獲取binlog,,存于本地relay-log中,,然后從上次記住的位置起執(zhí)行SQL語句,一旦遇到錯誤則停止同步,。 簡記:MySQL的主從復(fù)制,,實際上就是Master記錄自己的執(zhí)行日志binlog,然后發(fā)送給Slave,,Slave解析日志并執(zhí)行,,來實現(xiàn)數(shù)據(jù)復(fù)制。主服務(wù)器流程分析 首先bin-log日志文件加鎖,,然后讀取更新的操作,,讀取完畢以后將鎖釋放掉,最后將讀取的記錄發(fā)送給從服務(wù)器,。從服務(wù)器流程分析 在一次主從復(fù)制過程中需要用到三個線程:Binlog dump 線程,、Slave I/O 線程和Slave SQL線程,其中Binlog dump 線程在主服務(wù)器上面,,剩下的兩個線程是在從服務(wù)器上面工作的。 這兩個線程在從服務(wù)器上面的工作流程如下圖所示:如何提高Mysql主從復(fù)制的效率,? 1.master 端 master端有2個參數(shù)可以控制,。 Binlog_Do_DB : 設(shè)定哪些數(shù)據(jù)庫需要記錄Binlog。 Binlog_Ignore_DB : 設(shè)定哪些數(shù)據(jù)庫不要記錄Binlog,。 2.slave 端 slave端有6個參數(shù)可以控制,。 Replicate_Do_DB : 設(shè)定須要復(fù)制的數(shù)據(jù)庫,多個DB用逗號分隔,。 Replicate_Ignore_DB : 設(shè)定可以忽略的數(shù)據(jù)庫,。 Replicate_Do_Table : 設(shè)定須要復(fù)制的Table。 Replicate_Ignore_Table : 設(shè)定可以忽略的Table,。 Replicate_Wild_Do_Table : 功能同Replicate_Do_Table,,但可以帶通配符來進行設(shè)置。 Replicate_Wild_Ignore_Table : 功能同Replicate_Ig-nore_Table,,可帶通配符設(shè)置,。 數(shù)據(jù)庫的分庫分表 分表 對于訪問極為頻繁且數(shù)據(jù)量巨大的單表來說,我們首先要做的就是減少單表的記錄條數(shù),,以便減少數(shù)據(jù)查詢所需要的時間,,提高數(shù)據(jù)庫的吞吐,這就是所謂的分表,! 將原有的單表分為256個表 算法 :user_id%256 拆分后表的數(shù)量一般為2的n次方,,就是上面拆分成256張表的由來!分庫 分表能夠解決單表數(shù)據(jù)量過大帶來的查詢效率下降的問題,但是,,卻無法給數(shù)據(jù)庫的并發(fā)處理能力帶來質(zhì)的提升,。面對高并發(fā)的讀寫訪問,對數(shù)據(jù)庫進行拆分,,從而提高數(shù)據(jù)庫寫入能力,,這就是所謂的分庫! 將原有的單庫分為256個庫 算法 :user_id%256分庫分表 有時數(shù)據(jù)庫可能既面臨著高并發(fā)訪問的壓力,又需要面對海量數(shù)據(jù)的存儲問題,,這時需要對數(shù)據(jù)庫既采用分表策略,,又采用分庫策略,以便同時擴展系統(tǒng)的并發(fā)處理能力,,以及提升單表的查詢性能,,這就是所謂的分庫分表。 一種分庫分表的路由策略如下: 1. 中間變量 = user_id % (分庫數(shù)量 * 每個庫的表數(shù)量) 2. 庫 = 取整數(shù) (中間變量 / 每個庫的表數(shù)量) 3. 表 = 中間變量 % 每個庫的表數(shù)量舉例: 假設(shè)將原來的單庫單表order拆分成256個庫,,每個庫包含1024個表,,那么按照前面所提到的路由策略,對于user_id=262145 的訪問,,路由的計算過程如下: 1. 中間變量 = 262145 % (256 * 1024) = 1 2. 庫 = 取整 (1/1024) = 0 3. 表 = 1 % 1024 = 1 這就意味著,,對于user_id=262145 的訂單記錄的查詢和修改,將被路由到第0個庫的第1個order_1表中執(zhí)行?。,。?/span> 數(shù)據(jù)庫SQL優(yōu)化 1. 對查詢進行優(yōu)化,要盡量避免全表掃描,首先應(yīng)考慮在 where 及 order by 涉及的列上建立索引,。2. 應(yīng)盡量避免在 where 子句中對字段進行 null 值判斷,否則將導(dǎo)致引擎放棄使用索引而進行全表掃描,。如:select id from t where num is null 聚集索引和非聚集索引 聚集索引 聚集索引就是存放的物理順序和列中的順序一樣。一般設(shè)置主鍵索引就為聚集索引,。 一個沒加主鍵的表,,它的數(shù)據(jù)無序的放置在磁盤存儲器上,一行一行的排列的很整齊,。如果給表上了主鍵,,那么表在磁盤上的存儲結(jié)構(gòu)就由整齊排列的結(jié)構(gòu)轉(zhuǎn)變成了樹狀結(jié)構(gòu),也就是平衡樹結(jié)構(gòu),,換句話說,,就是整個表就變成了一個索引,也就是所謂的聚集索引,。 這就是為什么一個表只能有一個主鍵,, 一個表只能有一個聚集索引,因為主鍵的作用就是把表的數(shù)據(jù)格式轉(zhuǎn)換成索引(平衡樹)的格式放置,。 上圖就是帶有主鍵的表(聚集索引)的結(jié)構(gòu)圖,。其中樹的所有結(jié)點(底部除外)的數(shù)據(jù)都是由主鍵字段中的數(shù)據(jù)構(gòu)成,也就是通常我們指定主鍵的id字段,。最下面部分是真正表中的數(shù)據(jù),。 假如我們執(zhí)行一個SQL語句:select * from table where id = 1256 首先根據(jù)索引定位到1256這個值所在的葉結(jié)點,然后再通過葉結(jié)點取到id等于1256的數(shù)據(jù)行,。 這里不講解平衡樹的運行細節(jié),, 但是從上圖能看出,樹一共有三層,, 從根節(jié)點至葉節(jié)點只需要經(jīng)過三次查找就能得到結(jié)果,。如下圖 然而, 事物都是有兩面的,, 索引能讓數(shù)據(jù)庫查詢數(shù)據(jù)的速度上升,, 而使寫入數(shù)據(jù)的速度下降,,原因很簡單的, 因為平衡樹這個結(jié)構(gòu)必須一直維持在一個正確的狀態(tài),, 增刪改數(shù)據(jù)都會改變平衡樹各節(jié)點中的索引數(shù)據(jù)內(nèi)容,,破壞樹結(jié)構(gòu), 因此,,在每次數(shù)據(jù)改變時,, DBMS必須去重新梳理樹(索引)的結(jié)構(gòu)以確保它的正確,這會帶來不小的性能開銷,,也就是為什么索引會給查詢以外的操作帶來副作用的原因,。非聚集索引 講完聚集索引 , 接下來聊一下非聚集索引,, 也就是我們平時經(jīng)常提起和使用的常規(guī)索引,。 非聚集索引和聚集索引一樣, 同樣是采用平衡樹作為索引的數(shù)據(jù)結(jié)構(gòu),。索引樹結(jié)構(gòu)中各節(jié)點的值來自于表中的索引字段,, 假如給user表的name字段加上索引 , 那么索引就是由name字段中的值構(gòu)成,,在數(shù)據(jù)改變時,, DBMS需要一直維護索引結(jié)構(gòu)的正確性。如果給表中多個字段加上索引 ,, 那么就會出現(xiàn)多個獨立的索引結(jié)構(gòu),,每個索引(非聚集索引)互相之間不存在關(guān)聯(lián)。 如下圖 每次給字段建一個新索引,, 字段中的數(shù)據(jù)就會被復(fù)制一份出來,, 用于生成索引。 因此,, 給表添加索引,,會增加表的體積, 占用磁盤存儲空間,。 非聚集索引和聚集索引的區(qū)別在于: 通過聚集索引可以一次查到需要查找的數(shù)據(jù),, 而通過非聚集索引第一次只能查到記錄對應(yīng)的主鍵值 , 再使用主鍵的值通過聚集索引查找到需要的數(shù)據(jù),。 聚集索引一張表只能有一個,,而非聚集索引一張表可以有多個。 索引是什么,?有什么作用以及優(yōu)缺點? 索引是什么,? 數(shù)據(jù)庫引擎MyISAM和InnoDB InnoDB是非事務(wù)的存儲引擎,;適合用于頻繁查詢的應(yīng)用;表鎖,,不會出現(xiàn)死鎖,;適合小數(shù)據(jù),小并發(fā) InnoDB是支持事務(wù)的存儲引擎,;合于插入和更新操作比較多的應(yīng)用,;設(shè)計合理的話是行鎖(最大區(qū)別就在鎖的級別上);適合大數(shù)據(jù),,大并發(fā),。 MyISAM表的數(shù)據(jù)文件和索引文件是自動分開的;InnoDB的數(shù)據(jù)和索引是存儲在同一個表空間里面,,但可以有多個文件組成,。 為什么MyISAM會比InnoDB的查詢速度快 1.InnoDB要緩存數(shù)據(jù)塊,而MyISAM只緩存索引塊 2.InnoDB尋址要映射到塊,,再到行,,MyISAM記錄的直接是文件的OFFSET,定位比InnoDB要快 3.InnoDB還需要維護MVCC一致 慢查詢?nèi)罩?/strong> 慢查詢?nèi)罩靖拍?/span> MySQL的慢查詢?nèi)罩臼荕ySQL提供的一種日志記錄,,它用來記錄在MySQL中響應(yīng)時間超過閥值的語句,,具體指運行時間超過long_query_time值的SQL,則會被記錄到慢查詢?nèi)罩局?。long_query_time的默認值為10,,意思是運行10S以上的語句,。默認情況下,Mysql數(shù)據(jù)庫并不啟動慢查詢?nèi)罩?,需要我們手動來設(shè)置這個參數(shù),,當然,如果不是調(diào)優(yōu)需要的話,,一般不建議啟動該參數(shù),,因為開啟慢查詢?nèi)罩緯蚨嗷蛏賻硪欢ǖ男阅苡绊憽B樵內(nèi)罩局С謱⑷罩居涗泴懭胛募?,也支持將日志記錄寫入?shù)據(jù)庫表,。慢查詢?nèi)罩鞠嚓P(guān)參數(shù)slow_query_log :是否開啟慢查詢?nèi)罩荆?表示開啟,0表示關(guān)閉,。log-slow-queries :舊版(5.6以下版本)MySQL數(shù)據(jù)庫慢查詢?nèi)罩敬鎯β窂?。可以不設(shè)置該參數(shù),,系統(tǒng)則會默認給一個缺省的文件host_name-slow.logslow-query-log-file:新版(5.6及以上版本)MySQL數(shù)據(jù)庫慢查詢?nèi)罩敬鎯β窂?。可以不設(shè)置該參數(shù),,系統(tǒng)則會默認給一個缺省的文件host_name-slow.loglong_query_time :慢查詢閾值,,當查詢時間多于設(shè)定的閾值時,記錄日志,。log_queries_not_using_indexes:未使用索引的查詢也被記錄到慢查詢?nèi)罩局校蛇x項),。log_output:日志存儲方式。log_output='FILE'表示將日志存入文件,,默認值是'FILE',。慢查詢?nèi)罩九渲?/span> 默認情況下slow_query_log的值為OFF,表示慢查詢?nèi)罩臼墙玫?,可以通過設(shè)置slow_query_log的值來開啟,。mysql> show variables like '%slow_query_log%';+---------------------+------------------------------------------+| Variable_name | Value |+---------------------+------------------------------------------+| slow_query_log | OFF || slow_query_log_file | /usr/local/mysql/data/localhost-slow.log |+---------------------+------------------------------------------+2 rows in set (0.00 sec) mysql> set global slow_query_log=1;Query OK, 0 rows affected (0.00 sec) mysql> show variables like '%slow_query_log%';+---------------------+------------------------------------------+| Variable_name | Value |+---------------------+------------------------------------------+| slow_query_log | ON || slow_query_log_file | /usr/local/mysql/data/localhost-slow.log |+---------------------+------------------------------------------+2 rows in set (0.00 sec)#使用set global slow_query_log=1開啟了慢查詢?nèi)罩局粚Ξ斍皵?shù)據(jù)庫生效,MySQL重啟后則會失效,。如果要永久生效,,就必須修改配置文件my.cnf(其它系統(tǒng)變量也是如此) 修改my.cnf文件,增加或修改參數(shù)slow_query_log 和slow_query_log_file后,,然后重啟MySQL服務(wù)器,。slow_query_log =1slow_query_log_file=/usr/local/mysql/data/localhost-slow.logmysql> show variables like 'slow_query%';+---------------------+---------------------+| Variable_name | Value |+---------------------+---------------------+| slow_query_log | ON || slow_query_log_file | /usr/local/mysql/data/localhost-slow.log |+---------------------+---------------------+2 rows in set (0.00 sec) mysql> #慢查詢的參數(shù)slow_query_log_file ,它指定慢查詢?nèi)罩疚募拇娣怕窂?,系統(tǒng)默認會給一個缺省的文件host_name-slow.log日志分析工具mysqldumpslow 在實際生產(chǎn)環(huán)境中,,如果要手工分析日志,查找,、分析SQL,,顯然是個體力活,,MySQL提供了日志分析工具mysqldumpslow得到返回記錄集最多的10個SQL。mysqldumpslow -s r -t 10 /database/mysql/mysql06_slow.log 得到訪問次數(shù)最多的10個SQLmysqldumpslow -s c -t 10 /database/mysql/mysql06_slow.log 得到按照時間排序的前10條里面含有左連接的查詢語句,。mysqldumpslow -s t -t 10 -g “l(fā)eft join” /database/mysql/mysql06_slow.log 另外建議在使用這些命令時結(jié)合 | 和more 使用 ,,否則有可能出現(xiàn)刷屏的情況。mysqldumpslow -s r -t 20 /mysqldata/mysql/mysql06-slow.log | more XSS,、SQL和CSRF攻擊 XSS(Cross Site Script,,跨站腳本攻擊)是向網(wǎng)頁中注入惡意腳本在用戶瀏覽網(wǎng)頁時在用戶瀏覽器中執(zhí)行惡意腳本的攻擊方式。 防止方法:做數(shù)據(jù)校驗,、做標簽轉(zhuǎn)換,,如:空格 轉(zhuǎn)化為 。 SQL注入攻擊是注入攻擊最常見的形式,,當服務(wù)器使用請求參數(shù)構(gòu)造SQL語句時,,惡意的SQL被嵌入到SQL中交給數(shù)據(jù)庫執(zhí)行; 防止方法:輸入校驗,、sql不要動態(tài)拼接,,用參數(shù)化的sql。 CSRF攻擊(Cross Site Request Forgery,,跨站請求偽造)是攻擊者通過跨站請求,以合法的用戶身份進行非法操作(如轉(zhuǎn)賬或發(fā)帖等),。 CSRF的原理是利用瀏覽器的Cookie或服務(wù)器的Session,,盜取用戶身份; 防止方法:使用post代替get,,因為post不會被緩存,;每次清除掉cookie。 |
|