MySQL提高課程 全面講解MySQL架構設計

 

select語句 若是從文件中獲取咱們要查找的數據,這個具體的實現方式則有下面的存儲引擎實現css

myisam存儲引擎
一些系統表和臨時排序生成的表仍是myisam存儲引擎
myisam存儲引擎實現的表的存儲是有MYD文件和MYI文件 MYD存儲的是數據 MYI存儲的是索引 還有個frm文件是標識表的數據結構信息mysql

myisam存儲引擎所級別是表鎖
myisam存儲引擎 支持全文索引
myisam存儲引擎 支持表數據壓縮
myisam存儲引擎 不支持事務linux

 

=====================innodb系統表空間========================================
一、Innodb使用表空間進行數據存儲,根據配置參數innod_file_per_table
的值,若是是ON,則存儲在獨立表空間--tablename.idb,若是是OFF,則存儲
在系統表空間--ibdataX(默認是打開的)--> show variables like 'innodb_file_per_table;'程序員

二、系統表空間和獨立表空間要如何選擇:
系統表空間沒法簡單的收縮文件大小
獨立表空間能夠經過optimize table命令收縮文件系統
系統表空間會產生IO瓶頸
獨立表空間能夠經過向多個文件刷新數據sql

三、若是把原來存在系統表空間中的錶轉移到獨立表空間:
使用mysqldump導出全部數據庫數據
中止mysql服務,修改參數,並刪除innodn相關文件
重啓mysql服務,重建innodb系統表空間
從新導入數據
=====================innodb系統表空間========================================shell


=====================innodb特性========================================
一、Innodb是一種事務性存儲引擎
二、徹底支持事務的ACID特性
三、實現事務特性的原理:
使用Redo Log和Undo Log,Undo Log用於幫助未提交事務進行回滾,Redo Log記錄
已經提交的事務,Undo Log會隨機讀寫,而Redo Log基本是順序
四、Innodb支持的是行級鎖,在進行寫操做時須要的資源更少,支持的併發更多
五、行級鎖是由存儲引擎層實現的
六、鎖:
鎖的主要租用是管理共享資源的併發訪問
鎖用於實現事務的隔離性
共享鎖(讀鎖)
獨佔鎖(寫鎖)
鎖的粒度:根據粒度分爲表級鎖,行級鎖,粒度越大,併發就越小
七、阻塞和死鎖:
阻塞:一個事務中的鎖須要等待另外一個事務中的鎖釋放,造成的是阻塞
死鎖:兩個或兩個以上的事務在執行中相互佔用了對方的資源
八、Innodb狀態檢查:
show engine innodb status;數據庫

 

 

 

1:併發量:同一時間處理請求數量,同一時間處理請求數量和鏈接數量是兩個概念,鏈接數大於處理請求數量,centos

     MySQL參數最大鏈接數max_connections緩存

 這是是查詢數據庫當前設置的最大鏈接數
  mysql> show variables like '%max_connections%';


2:最好不要在大型活動時候在主庫上進行數據庫備份會佔用很大磁盤io
3:影響數據庫性能的因素:服務器硬件,磁盤io,sql查詢速度,網卡流量安全

  1. 網卡流量控制策越
  2. 減小從服務器數量
  3. 多級緩存
  4. 避免select *


4:老版本不支持多cpu對同一sql的併發處理
5:QPS:每秒鐘處理的請求量
6:大表問題:單表超過千萬行,表數據文件超過10g,
會致使慢查詢很難在必定的時間內查詢出所須要的數據,致使大量的磁盤io
創建索引須要更長的時間,5.5版本以前會引起鎖表5.5版本以後隨便不會鎖表,可是會引發主從延遲
修改表結構須要長時間鎖表引發主從延遲

7:能夠經過分表來解決大表問題,可是分表也面臨着兩個難點(1)分表主鍵的選擇(2)分表後的跨表查詢
8:能夠經過數據歸檔來解決大表問題,可是一樣面臨着兩個問題(1)數據歸檔時間點的選擇(2)以及若是進行歸檔操做

9:事務:原子性,一致性,隔離性,永久性
10:大事務會致使鎖定太多的數據形成大量的阻塞和超時,回滾須要更長的時間,執行時間長,容易形成主從延遲
11:解決大事務有兩點(1)避免一次性處理不少數據(2)在事務中移除沒必要要的語句如select語句

12:數據庫類型的選擇對數據庫的性能影響很大 

1 . 數據類型會影響存儲空間的開銷

2 . 數據類型會影響數據查詢性能

因此當一個數據類型能夠有多種選擇多種類型的時候,應該優先考慮數字類型,其次是日期或二進制類型,最後應該是字符類型。對於相同級別的數據類型,應該優先選擇佔用空間小的數據類型。 
原理:在對數據進行比較(查詢條件,JOIN條件及排序)操做時:一樣的數據,字符處理每每比數字處理慢,並且在數據庫中,數據的處理是以頁爲單位,列的長度越小,數據類型佔用的空間越小,利於性能的提高。

13:int整型

年齡:tinyint(1) 0-255之間

烏龜年齡: smallint(2)

mediumint(3)

int(4)

bigint(8)

 

 

14:int(11)表明什麼意思

11表明的並非長度,而是字符的顯示寬度,在字段類型爲int時,不管你顯示寬度設置爲多少,int類型能存儲的最大值和最小值永遠都是固定

 

因此不管怎麼設置int類型的顯示寬度,int所能存儲的最大值和最小值是固定的,那麼這個顯示寬度到底有什麼用呢?
當int字段類型設置爲無符號填充零(UNSIGNED ZEROFILL)時,當數值位數未達到設置的顯示寬度時,會在數值前面補充零直到知足設定的顯示寬度,爲何會有無符號的限制呢,是由於ZEROFILL屬性會隱式地將數值轉爲無符號型,所以不能存儲負的數值。

 

15:如何選擇正確的實數類型

列類型 存儲空間 是否精確
FLOAT 4個字節 否
DOUBLE 8個字節 否
DECIMAL(與金額有關的) 每4個字節存9個數字,小數點佔一個字節 否
DECIMAL(18,9):表示該字段可存儲數字最大的長度是18位,其中小數位最大的長度是9位。因爲DECIMAL每4個字節存9個數字,小數點佔一個字節,因此該字段佔9個字節
---------------------

 

 

16:如何選擇VARCHAR和CHAR類型

VARCHAR和CHAR類型長度是以字符爲定位的而不是字節,如UTF-8編碼,每一個字符佔3個字節,那麼CHAR(10)就須要佔30個字節


長度:65535字節限制

存儲漢字,例如字符集utf8的(每一個漢字佔據3個字節),最多能夠存儲65535/3-2字節

VARCHAR類型的存儲特色

  • VARCHAR用於存儲變長字符串,只佔用必要的存儲空間。
  • 當列的最大長度小於255時,只佔用一個額外字節用於記錄字符串長度。
  • 當列的最大長度大於255,則須要佔用兩個額外字節用於記錄字符串長度。

VARCHAR長度選擇問題

  • 使用最小的符合需求的長度。
  • 系統上線後儘可能不要修改VARCHAR的長度,由於在mysql 5.7以前,只要一修改就會發生鎖表。
  • VARCHAR(5)和VARCHAR(200)存儲'AAAAA'這一個字符串時都是使用一個額外的字節來記錄字符串的長度,那麼他們的性能有什麼不一樣呢?
  • VARCHAR(5)優於VARCHAR(200)。由於MySQL爲了可以更有效的優化查詢,對於VARCHAR字段使用的是其最大的寬度來分配內存,因此若是咱們把寬度定的太長就會消耗更多的內存。

VARCHAR類型的適用場景

  • 字符串列的最大長度比平均長度大不少
  • 字符串列不多被更新
  • 使用了多字節字符集存儲字符串(如utf8中的中文和英文)


CHAR類型的存儲特色

  • CHAR類型是定長的
  • 字符串存儲在CHAR類型的列中會刪除末尾的空格(VARCHAR則不會)
  • CHAR類型的最大寬度是255個字符,因此若是當咱們長度超過255時,則須要使用VARCHAR類型進行存儲

CHAR類型的適用場景

  • 存儲長度近似的值(md5值,如密碼)
  • 存儲短字符串
  • 存儲常常被更新的字符串列,mysql在運行中會一次性分配足夠的內存,多頻繁的更新不會形成列分裂,避免超出存儲碎片

 17:如何選擇日期類型

    DATATIME類型
DATATIME = yyyy-MM-dd HH:mm:ss
以YYYY-MM-DD HH:MM:SS[.fraction]格式存儲日期時間,能支持微秒可是默認仍是支持秒
若是咱們要支持微秒要定義個長度
datetime(6)=YYYY-MM-DD HH:MM:SS.fraction
與時區無關,佔8個字節的存儲空間
時間範圍:1000-1-1 00:00:00至9999-12-31 23:59:59

TIMESTAMP類型

存儲了由格林尼治時間1970-1-1 00:00:00到當前時間的秒數,
以yyyy-MM-dd HH:mm:ss[.fraction]的格式顯示,佔用4個字節
時間範圍:1970-1-1 到 2038-01-19
顯示依賴於所指定的時區
在行的數據修改時能夠自動修改TIMESTAMP列的值(設置爲NOT NULL便可),
默認是第一個爲TIMESTAMP類型的列纔會自動更新

DATE類型(如生日)

佔用3個字節
使用DATE類型能夠利用日期函數進行日期之間的計算
範圍:1000-01-01到9999-12-31

TIME類型
HH:MM:SS
注意事項:
不要使用字符串類型存儲日期時間數據
日期時間類型一般比字符串佔用空間小
日期類型在進行查找過濾時能夠利用日期來進行對比
能夠利用日期函數進行日期之間的計算
使用Int存儲日期時間不如使用TIMESTAMP類型
由於TIMESTAMP類型底層其實也是使用INT來存儲的,只不過顯示的時候格式化了而已,但更方便查看

18:
innodb的主鍵
innodb是基於聚簇索引創建的. 聚簇索引對主鍵查詢有很高的性能. 但它的二級索引(非主鍵索引)中必須包含主鍵列, 因此若是主鍵列很大的話, 其餘的全部索引都會很大. 所以, innodb的主鍵應該儘量小
這也是爲何InnoDB爲何最好選擇自增int型做爲主鍵的緣由之一;
另外一個緣由是使用遞增型做爲主鍵, 存儲引擎在插入數據時, 不會出現裂頁插入的現象, 由於是append添加數據,
同時遞增型做爲主鍵能夠順序插入,避免隨機io, 增長插入效率不遞增,每次插入都會從新排序
19:利用二進制日誌增量複製不須要太多的寬帶,可是大批量基於行的複製會佔用很大寬帶,特別是在跨idc的環境下

20:
MySQL日誌分爲
    MySQL服務層日誌  
二進制日誌、慢查詢日誌、通用日誌。   
MySQL存儲引擎層日誌        
如innodb的重作日誌和回滾日誌 

21:
二進制日誌:記錄了全部對MySQL數據庫的修改事件,包括在刪改查和對錶結構的修改事件。

記載的都是成功執行了的,但對於回滾的語句是不會記載在binlog日誌中的。

查看binlog日誌格式:

show variables like "binlog_format";
set global binlog_format='MIXED';
set session binlog_format='MIXED';
二進制日誌類型分爲
基於段的格式 binlog_format = STATEMENT (記錄sql語句)
binlog_format=statement
優勢:日誌記錄量相對較小,節約磁盤及網絡i/o,只對一條記錄修改或插入
缺點:必需要記錄上下文信息(保證語句在從服務器和主服務器上執行結果同樣),
對於特定的函數如uuid(),user()這樣的非肯定函數仍是沒法複製,可能形成mysql複製的主備服務器數據不一致

        
基於行的格式 binlog_format = ROW 推薦 
同一sql語句修改10000條數據的狀況下,基於段的日誌格式只會記錄這個sql語句,
基於行的日誌格式會有10000條記錄分別記錄每一行的數據修改
優勢:使mysql主從複製更加安全,對每一行數據的修改比基於段的複製高效,誤操做而修改了數據庫中的數據,
同時又沒有備份能夠恢復時,咱們就能夠經過分析二進制日誌,對日誌記錄的數據修改操做作反向處理的方式來達到
恢復數據的目的
缺點:記錄日誌量較大
版本介紹5.6.2裏新增函數binlog_row_image。是動態參數,使用級別session和global。
可選值
full:
默認值,記錄全部的行信息,和5.6以前記錄的沒有區別
minimal:
只記錄要修改列的記錄
noblob:
記錄除了blog和text以外的全部字段
須要注意的是,只有在row格式下,上面的參數纔會支持,就是說上面的參數是基於binlog_format的格式的。

binlog_format =Mixed
從 5.1.8 版本開始,MySQL 提供了除 Statement 和 Row 以外的第三種複製模式:Mixed,
實際上就是前兩種模式的結合。
在 Mixed 模式下,MySQL 會根據執行的每一條具體的 SQL 語句來區分對待記錄的日誌形式,
也就是在 statement 和 row 之間選擇一種。

22:
刷新log日誌,自此刻開始產生一個新編號的binlog日誌文件
mysql> flush logs;
注:每當mysqld服務重啓時,會自動執行此命令,刷新binlog日誌;在mysqldump備份數據時加 -F 選項也會刷新binlog日誌;
獲取binlog文件列表 
mysql> show binary logs;
經過mysqlbinlog命令能夠查看binlog的內容
mysqlbinlog /home/mysql/binlog/binlog.000003 | 
 23:MySQL二進制日誌格式對複製的影響
複製的分類
基於SQL語句的複製 - SBR
主庫二進制日誌格式使用STATEMENT
在MySQL 5.1以前僅存在SBR模式, 又稱之爲邏輯複製.
主庫記錄CUD操做的SQL語句, 從庫會讀取並重放.
優勢
生成的日誌量少, 節約網絡傳輸IO
當主從的列的順序不一致時, SBR依然能夠正常工做.
如對大表進行結構修改時, 能夠先修改從庫, 而後再進行主從切換.
缺點
對不肯定性函數沒法保證主從數據的一致
對於procedure, trigger, function有可能在主從上表現不一致(SBR BUG)
主庫上要鎖定多少行, 從庫上也須要因此多少行, 因此相對於ROW複製時從庫上須要更多的行鎖

基於行的複製 - RBR
主庫二進制日誌格式使用ROW
優勢
對不肯定性函數友好, 如UUID()
減小從庫上數據庫鎖的使用
insert into t_order_cnt(timestr, total, amount)
select date(order_date), count(1), sum(amout)
from t_order group by date(order_date);
1
2
3
1
2
3
上面的SQL在主庫執行時會對t_order進行鎖表操做, 對於STATEMENT的複製從庫上也會對一樣的表進行鎖定,
可是基於ROW的複製僅需增長t_order對應的行的數據便可.
缺點
要求主從數據庫的表的結構一致, 不然可能會中斷複製
沒法在從庫上激活trigger


24:
Mysql主從複製的實現原理圖大體以下(來源網絡):

MySQL之間數據複製的基礎是二進制日誌文件(binary log file)。一臺MySQL數據庫一旦啓用二進制日誌後,其做爲master,它的數據庫中全部操做都會以「事件」的方式記錄在二進制日誌中,其餘數據庫做爲slave經過一個I/O線程與主服務器保持通訊,並監控master的二進制日誌文件的變化,若是發現master二進制日誌文件發生變化,則會把變化複製到本身的中繼日誌中,而後slave的一個SQL線程會把相關的「事件」執行到本身的數據庫中,以此實現從數據庫和主數據庫的一致性,也就實現了主從複製。

實現MySQL主從複製須要進行的配置:

    • 主服務器:
      • 開啓二進制日誌
      • 配置惟一的server-id
      • 得到master二進制日誌文件名及位置
      • 建立一個用於slave和master通訊的用戶帳號
    • 從服務器:
      • 配置惟一的server-id
      • 使用master分配的用戶帳號讀取master二進制日誌
      • 啓用slave服務

具體實現過程以下:

1、準備工做:

1.主從數據庫版本最好一致

2.主從數據庫內數據保持一致

主數據庫:182.92.172.80 /linux

從數據庫:123.57.44.85 /linux

2、主數據庫master修改:

1.修改mysql配置

找到主數據庫的配置文件my.cnf(或者my.ini),個人在/etc/mysql/my.cnf,在[mysqld]部分插入以下兩行:

[mysqld]
bin_log =mysql-bin #開啓二進制日誌
server-id=1 #設置server-id

2.重啓mysql,建立用於同步的用戶帳號

打開mysql會話shell>mysql -hlocalhost -uname -ppassword

建立用戶並受權:用戶:rel1密碼:slavepass

mysql> CREATE USER 'repl'@'123.57.44.85' IDENTIFIED BY 'slavepass';#建立用戶
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'123.57.44.85';#分配權限
mysql>flush privileges;   #刷新權限

3.查看master狀態,記錄二進制文件名(mysql-bin.000003)和位置(73):

mysql > SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 | 73       | test         | manual,mysql     |
+------------------+----------+--------------+------------------+

 

初始化從服務器數據

對數據庫進行備份

mysqldump --single-transaction --master-data=2 --triggers --routines --all-databases -uroot -p >all.sql

將備份拷貝到從庫上

scp all.sql root@192.168.3.101:/tmp

在從庫上恢復數據

mysql -uroot -p <all.sql

在從庫上查看all.sql的內容

more all.sql 並記錄change master的內容



2、從服務器slave修改:

1.修改mysql配置

一樣找到my.cnf配置文件,添加server-id

[mysqld]
server-id=2 #設置server-id,必須惟一
bin_log = mysql-bin

  relay_log = mysql-relay-bin

  log_slave_update = on (可選)

  read_only = on

2.重啓mysql,打開mysql會話,執行同步SQL語句(須要主服務器主機名,登錄憑據,二進制文件的名稱和位置):

mysql> CHANGE MASTER TO
    ->     MASTER_HOST='182.92.172.80',
    ->     MASTER_USER='rep1',
    ->     MASTER_PASSWORD='slavepass',
    ->     MASTER_LOG_FILE='mysql-bin.000003',
    ->     MASTER_LOG_POS=73;

3.啓動slave同步進程:

mysql>start slave;

4.查看slave狀態:

複製代碼
mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 182.92.172.80
                  Master_User: rep1
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000013
          Read_Master_Log_Pos: 11662
               Relay_Log_File: mysqld-relay-bin.000022
                Relay_Log_Pos: 11765
        Relay_Master_Log_File: mysql-bin.000013
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
        ...
複製代碼

當Slave_IO_Running和Slave_SQL_Running都爲YES的時候就表示主從同步設置成功了。接下來就能夠進行一些驗證了,好比在主master數據庫的test數據庫的一張表中插入一條數據,在slave的test庫的相同數據表中查看是否有新增的數據便可驗證主從複製功能是否有效,還能夠關閉slave(mysql>stop slave;),而後再修改master,看slave是否也相應修改(中止slave後,master的修改不會同步到slave),就能夠完成主從複製功能的驗證了。

還能夠用到的其餘相關參數:

master開啓二進制日誌後默認記錄全部庫全部表的操做,能夠經過配置來指定只記錄指定的數據庫甚至指定的表的操做,具體在mysql配置文件的[mysqld]可添加修改以下選項:

複製代碼
# 不一樣步哪些數據庫  
binlog-ignore-db = mysql  
binlog-ignore-db = test  
binlog-ignore-db = information_schema  
  
# 只同步哪些數據庫,除此以外,其餘不一樣步  
binlog-do-db = game  
複製代碼

如以前查看master狀態時就能夠看到只記錄了test庫,忽略了manual和mysql庫。

25:把中繼日誌的內容加入到slave的binlog中。也就是說slave的binlog會記錄master同步的操做日誌。
log-slave-updates=on

26: 基於日誌點複製的優勢:
1.MySQL最先支持的複製技術,BUG相對較少。
2.對sql查詢沒有什麼限制。
3.故障處理比較容易。
基於日誌點複製的缺點:
1.故障轉移時從新獲取master的日誌點信息比較困難。基於日誌點複製是從master的binlog的偏移量進行增量同步。若是指定錯誤會形成遺漏或者重複,形成主從不一致。

27:
基於GTID複製

GTID是全局事務ID,其保證爲每一個在master上提交的事務在複製集羣中能夠生產一個惟一ID。GTID的生成策略是source_id(也就是server的uuid,在auto.conf文件裏面能夠看到):transaction_id(自增序列)。

[auto] server-uuid=67ccaaf1-e4b4-11e7-a07f-c8d3ffc0c026 

在基於GTID的複製中,slave會告訴master,slave已經執行事務的 GTID,master也會告訴slave,slave未執行事務的GTID。同一個事務只會在指定的從庫執行一次。

基於GTID複製的優勢是:

1.能夠很方便的進行故障轉移,記錄master最後事務的GTID值。好比master:A,slave:B,C。當A掛了後,B執行了全部A傳過來的事務。當C鏈接到B後,在本身的binlog找到最後一次A傳過來的GTID。而後C將這個GTID發送給B,B獲取到這個GTID,就開始從這個GTID的下一個GTID開始發送事務給C。這種自我尋找複製位置的模式減小事務丟失的可能性以及故障恢復的時間。

2.slave不會丟失master的任何修改(開啓了log_slave_updates)

基於GTID複製的缺點:
1.不支持非事務引擎。
2.故障處理比較複雜,須要注入空事務。
3.不支持sql_slave_skip_counter(通常用這個來跳過基於binlog主從複製出現的問題。)
4.對執行的sql有必定的限制。
5.爲了保證事務的安全性,create table ... select沒法使用。不能使用create temporary table建立臨時表。不能使用關聯更新事務表和非事務表。


28:基於GTID主從複製的步驟:
1.master數據改變時,會在事務前產生一個GTID,經過binlog dump記錄到master的binlog中。
2.slave經過IO Thread將binlog中變動的數據,寫入到slave的relay log中(中繼日誌)。
3.slave經過sql Thread讀取relay log中的GTID,而後對比slave的binlog是否有此記錄。
4.若是slave的binlog存在該GTID的記錄,那麼很差意思,忽略掉了。
5.若是slave的binlog不存在該GTID的記錄,那麼就執行該GTID事務,並一同記錄到slave的binlog中。
 
 

主服務器配置

[mysqld]
bin_log =mysql-bin #開啓二進制日誌
server-id=1 #設置server-id
gtid_mode=on
enforce-gtid-consistency=on
log-slave-updates=on

從服務器配置

[mysqld]
bin_log =mysql-bin #開啓二進制日誌
server-id=1 #設置server-id
gtid_mode=on
enforce-gtid-consistency=on
log-slave-updates=on

 

change master to master_host='127.0.0.1', master_port=3306, master_user='rpl', master_password='123', MASTER_AUTO_POSITION=1;

其餘和日誌點複製同樣

 

影響主從延遲的因素

  • 主庫執行事務到二進制日誌的時間
    • 控制主庫的事務大小,分割大事務
  • 二進制日誌傳輸的時間
    • 使用MIXED日誌或設置set binlog_row_image=minimal;
  • 默認狀況下從庫只有一個SQL線程,主上併發的修改在從上變成了串行
    • 使用多線程複製5.6版本開始

       

    • 在Mysql5.7中能夠按照邏輯時鐘的方式來分配SQL線程

如何配置多線程複製
stop slave;
set gloab slave_parallel_type='logical_clock';  #設置邏輯時鐘
set global slave_parallel_workers=4 #設置併發線程
start slave;
mysql> show processlist;    #查看當前mysql的運行線程

29:分庫分表
   把一個數據庫拆分紅多個數據庫
把多個數據庫分配在不一樣的數據庫實例節點上
把同一個數據庫中的某一個表分配在不一樣的數據庫實例上名字同樣構相同的表
把同一個數據庫中的某一個表分配成多個不一樣名字的表結構相同的表(水平拆分)
把同一個數據庫中的某一個表根據業務不一樣分配成多個不一樣名字結構也不相同的表(垂直拆分)

30:數據庫分片前的準備
    如何選擇分區鍵
分區鍵要能儘可能避免跨分區查詢的發生。例如一個博客表,若是採用每一篇博客的主鍵ID來進行分區,查詢某個用戶的博客時則要跨多個分區去彙總數據,性能會比分區前更慢。因此能夠考慮使用用戶ID來進行分區,則只須要在一個分片中進行查詢
分區鍵要能儘可能使各個分片中的數據平均。分片就是爲了減輕數據庫的負載,若是分片後許多查詢和更新都集中在一個分片上那分片就意義不大了
如何存儲無需分片的表
每一個分片中存儲一份相同的數據。這種方法適合數據量小的表,能夠提高關聯查詢的效率。
使用額外的節點統一存儲。
如何在節點上部署分片
每一個分片使用單一數據庫,而且數據庫名也相同
將多個分片表存儲在一個數據庫中,並在表名上加入分片號後綴
在一個節點中部署多個數據庫,每一個數據庫包含一個分片
如何分配分片中的數據
按分區鍵的Hash值取模來分配分片數據
按分區鍵的範圍來分配分區數據
利用分區鍵和分片的映射表來分配分片數據
如何生成全局惟一ID
使用auto_increment_increment和auto_increment_offset參數
使用全局節點來生成ID
在Redis等緩存服務器中建立全局ID

31:
如何獲取有性能問題的SQL
1.經過用戶反饋獲取存在性能問題的SQL.
2.經過慢查日誌獲取存在性能的SQL.
啓動慢查日誌
slow_query_log=on
set global slow_query_log=on;
slow_query_log_file 指定慢查日誌存儲路徑及文件
默認狀況保存在mysql的數據目錄中,最好日誌存儲和數據存儲分開。
long_query_time
指定記錄慢查日誌SQL執行時間的閥值,單位爲秒,默認值爲10秒。精確到微秒,
若是爲一毫秒這個值爲 0.001 。
記錄的語句包括
1.查詢語句
2.數據修改語句
3.已經回滾的SQL
log_queries_not_using_indexes 是否記錄未使用索引的SQL

慢查日誌中記錄的內容:

image

第一行記錄了:

用戶信息,線程ID號 用戶信息 sbtest ,線程ID爲 17

第二行 :記錄了查詢時間

第三行 :鎖的時間

第四行 : 返回的記錄行數

第五行: 掃描的行數

第六行 : 執行的時間

第七行 : 執行的語句

經常使用慢查詢日誌分析工具

1.mysqldumpslow

彙總除查詢條件外其餘徹底相同的SQL,並將分析結果按照參數中指定的順序輸出。

mysqldumpslow –s r –t 10 slow.log

-s order (c,t,l,r,at,al,ar)

c: 總的次數

t:總的時間

l:鎖的時間

r: 總數據行

at,al,ar: t,l,r 的平均數

at 總時間 /總次數

-t top 指定取前幾條做爲結果輸出

2.pt-query-digest

pt-query-digest –explain -h=127.0.0.1,u=root,p=root slow.log>slow.report

能夠包括執行計劃。


3.實時獲取性能的問題的SQL

select id,user,host,db,command ,time,state,info from information_schema.processlist where time>60;

查詢服務器中查詢時間超過60秒的SQL.



31:
查詢速度爲何會慢

SQL請求處理步驟
客戶端發送SQL請求給MySQL服務器
MySQL服務器會在查詢緩存中進行檢查,查看是否能夠在查詢緩存中命中
服務端會對SQL進行解析、預處理再由優化器生成對應的執行計劃
根據執行計劃,調用存儲引擎中的API來查詢數據
將查詢的數據返回給客戶端
32:
查詢緩存

若是查詢緩存開關是打開的會優先對緩存中檢查:
這個檢查是對大小寫敏感的hash查找實現:so,只能進行全值匹配查找。
若是在緩存中命中查詢結果,會進行角色的權限認證,而後跳事後面的步驟把數據返回給客戶端。
1. 查詢的SQL要和緩存中的徹底一致,因此命中並不容易。
2. 若是緩存中的數據是正確的,須要每次修改表的時候進行緩存的維護。
3. 並且進行緩存中查找的同時會對錶加鎖,因此對讀寫頻繁的應用,查詢緩存極可能下降查詢效率(不建議開啓查詢緩存)

查詢緩存相關參數
query_cache_type:
0表明關閉查詢緩存OFF,1表明開啓ON,2(DEMAND)表明當sql語句中有SQL_CACHE關鍵詞時才緩存。
例:select SQL_CACHE user_name from users where user_id = ‘100’;
query_cache_size:
表示查詢緩存大小,也就是分配內存大小給查詢緩存,分配大小爲1024整數倍;設置爲0表示不緩存
query_cache_limit :
控制緩存查詢結果的最大值
MySql 能夠設置一個最大的緩存值,當你查詢緩存數結果數據超過這個值就不會
進行緩存。缺省爲1M,也就是超過了1M查詢結果就不會緩存。
在 query_cache_type 打開的狀況下,若是你不想使用緩存,須要使用sql_no_cache關鍵字
例:select sql_no_cache id,name from tableName;
query_cache_wlock_invalidate:
若是一個表被加鎖是否容許直接從緩存中讀取結果,默認爲FALSE。
query_cache_min_res_unit:
查詢緩存中存放的最小內存大小,默認4k;

SQL轉變爲執行計劃
1:解析SQL
語法解析階段是經過關鍵字對mysql進行語法解析並生成一顆對應的解析樹
此階段,使用MySQL語法規則驗證和解析查詢:檢查語法是否使用的正確的關鍵字和關鍵字的位置是否正確
2:預處理
預處理階段進一步的驗證檢查解析樹是否合法
此階段檢查查詢中所涉及的表和數據列是否存在及名字或者別名是否有存在歧義
3:優化SQL執行計劃
查詢優化器生成查詢計劃
影響查詢計劃生成的因素

  1. 統計信息不許確
  2. 執行計劃中的成本估算並不等於實際的執行計劃成本
  3. mysql服務器層並不知道哪些頁面在內存中,哪些頁面在磁盤中,哪些頁面順序讀,哪些頁面要隨機讀
  4. mysql所認爲的最優可能和咱們所認爲的最優並不一致
  5. mysql基於其成本模型選擇最優的執行計劃
  6. mysql不會考慮到其餘的併發查詢
  7. 有時候也會基於一些固定的規則來生成執行計劃
  8. mysql不會考慮不受其控制的成本,如:存儲過程和用戶自定義的函數

MySQL能夠優化的SQL類型

  1. mysql會從新定義標的關聯順序
  2. 將外連接轉換成內鏈接
  3. 使用等價變換原則
  4. 能夠利用索引對count(),min(),max()進行優化。如最小值 btree索引第一個數據
  5. 將表達式轉化爲一個常數
  6. 子查詢優化:把子查詢轉換成關係查詢
  7. 會提早終止查詢:如發現不成立的條件,如屬性設置爲正數,查詢條件是負數
  8. 對in()進行優化,會對in中的數據進行排序,而後進行二分查找

如何肯定查詢各個階段所消耗的時間
profile
Profiling是從 mysql5.0.3版本之後纔開放的。
啓動profile以後,全部查詢包括錯誤的語句都會記錄在內。
profile是一個session級別的配置,關閉會話或者set profiling=0 就關閉了。(若是將profiling_history_size參數設置爲0,一樣具備關閉MySQL的profiling效果。)
show profiles
show profile for query N 查詢每一個階段所消耗的時間
5.5以後使用performance_schma
---------------------

32:特定sql語句的優化

  對大表的數據更新和刪除進行批量操做同時連續操做須要中間暫停間隔
如何修改大表的數據結構
對大表的字段和字段的寬度進行變動時候都會鎖表,同時沒法解決數據庫延遲的問題
能夠經過如下操做來完成大表的表結構變動
新建一張一樣的表結構
對老表進行數據同步
對老表進行存儲過程和觸發器的同步
對新表重命名
以上三個步驟能夠經過一個工具完成
pt-online-schema-change
--alter="modify c varchar(150) not null default''"
--user=root --password=PassWord D=testDataBaseName,t=tesTableName
--charset=utf-8 --execute

如何優化not in和<>查詢
#原始的SQL語句
SELECT
customer_id,
first_name,
last_name,
email
FROM
customer
WHERE
customer_id NOT IN (
SELECT
customer_id
FROM
payment
)

#優化後的SQL語句
SELECT
a.customer_id,
a,
first_name,
a.last_name,
a.email
FROM
customer a
LEFT JOIN payment b ON a.customer_id = b.customer_id
WHERE
b.customer_id IS NULL

使用匯總表的方法進行優化
#統計商品的評論數(如有上億條記錄,執行起來很是慢進行全表掃描)[優化前的SQL]
select count(*) from product_comment where product_id=999;
#彙總表就是提早以要統計的數據進行彙總並記錄到數據庫中以備後續的查詢使用
create table product_comment_cnt(product_id int,cnt int);
#統計商品的評論數[優化後的SQL]
#查詢出每一個商品截止到前一天的累計評論數+當天的評論數
select sum(cnt) from(
select cnt from product_comment_cnt where product_id=999
union all
select count(*) from product_comment where product_id=999
and timestr>DATE(NOW())
) a

33:
B-tree索引
B-tree索引可以加快數據的查詢速度(MySQL使用B+Tree)
由於存儲引擎再也不須要進行全表掃描來獲取數據,數據分佈在各個節點之中。
B+Tree 索引更適合進行範圍查找
​ 是B-Tree的改進版本,同時也是數據庫索引索引所採用的存儲結構。數據都在葉子節點上,
而且增長了順序訪問指針,每一個葉子節點都指向相鄰的葉子節點的地址。相比B-Tree來講,
進行範圍查找時只須要查找兩個節點,進行遍歷便可。而B-Tree須要獲取全部節點,
相比之下B+Tree效率更高。

什麼狀況下可使用B-tree索引
全值匹配的查詢
order_sn = 「987654321」
匹配最左前綴的查詢
匹配列前綴查詢
order_sn like 「9876」
匹配範圍值的查詢
order_sn > ‘987654321’ and order_sn < ‘98765444111’
精確匹配左前列並範圍匹配另一列
只訪問索引的查詢
B-tree索引的使用限制
若是不是按照索引最左列開始查找,則沒法使用索引
使用索引是不能跳過索引中的列(三個組合索引的狀況)
Not in 和 <> 操做沒法使用索引
若是查詢中有某個列的範圍查詢,則其右邊全部列都沒法使用索引


34:hash索引
  基於哈希表實現,只有精確匹配索引全部列的查詢纔有效,對於每一行數據,
存儲引擎都會對全部的索引列的值計算一個哈希碼,哈希碼是一個較小的值,
而且不一樣鍵值的行計算出來的哈希碼不同,哈希索引將全部的哈希碼存儲在索引中,
同時在哈希表中保存指向每一個數據行的指針。

mysql> select * from testhash;

+-------+-----------+
| fname | lname |
+-------+-----------+
| Arjen | Lentz |
| Baron | Schwartz |
| Peter | Zaitsev |
| Vadim | Tkachenko |
+-------+-----------+
4 rows in set (0.00 sec)

假設索引使用假想的哈希函數f(),它返回下面的值:
f('Arjen')=2323
f('Baron')=7437
f('Peter')=8784
f('Vadim')=2458

則哈希索引的數據結構以下:
槽: 值:
2323 指向第1行的指針
2458 指向第4行的指針
7437 指向第2行的指針
8784 指向第3行的指針
哈希索引自身只須要存儲對應的哈希值,因此索引的結構十分緊湊,這讓哈希索引查找的速度很是快

哈希索引限制
A:hash索引必須進行二次查找,哈希索引只包含哈希值和行指針,而不存儲字段值,
因此不能使用索引中的值來避免讀取行(即不能使用哈希索引來作覆蓋索引掃描),不過,訪問內存中的行的速度很快
(由於memory引擎的數據都保存在內存裏),因此大部分狀況下這一點對性能的影響並不明顯。

B:hash索引沒法用於排序,哈希索引數據並非按照索引列的值順序存儲的,因此也就沒法用於排序

C:哈希索引也不支持部分索引列匹配查找,由於哈希索引始終是使用索引的所有列值內容來計算哈希值的.如:數據列(a,b)上創建哈希索引,若是隻查詢數據列a,則沒法使用該索引

D:哈希索引只支持等值比較查詢,如:=,in(),<=>(注意,<>和<=>是不一樣的操做),不支持任何範圍查詢(必須給定具體的where條件值來計算hash值,因此不支持範圍查詢)
E:hash索引中hash碼的計算可能存在hash衝突


35:爲何要使用索引
索引大大減小了存儲引擎須要掃描的數據量
索引能夠幫助咱們進行排序以免使用臨時表
索引能夠把隨機I/o變成順序I/o
36:
索引是否是越多越好
  • 索引會增長寫操做的成本
  • 太多的索引會增長查詢優化器的選擇時間

37:索引細節

     索引優化策略

      索引列上不能使用表達式或函數
前綴索引和索引列的選擇性
索引的選擇性是不重複的索引值和表的記錄數的比值
聯合索引如何使用索引列的順序
常常會被使用到的列優先
選擇性高的列優先
寬度小的列優先
38:
覆蓋索引
一般開發人員會根據查詢的where條件來建立合適的索引,
可是優秀的索引設計應該考慮到整個查詢。其實mysql可使用索引來直接獲取列的數據。
若是索引的葉子節點包含了要查詢的數據,那麼就不用回表查詢了,
也就是說這種索引包含(亦稱覆蓋)
全部須要查詢的字段的值,咱們稱這種索引爲覆蓋索引。

覆蓋索引
優勢:
一、能夠優化緩存,減小磁盤IO操做
二、能夠減小隨機IO,使隨機IO操做變爲順序IO操做
三、能夠避免對Innodb主鍵索引的二次查詢
四、能夠避免MyISAM表進行系統調用

沒法使用覆蓋索引的狀況
一、存儲引擎不支持覆蓋索引
二、查詢中使用了太多的列
三、使用了雙%號的like查詢
 

覆蓋索引

若是一個索引包含(或者覆蓋)全部須要查詢的字段的值,則稱之爲覆蓋索引,優勢以下:

  • 索引條目一般遠小於數據行大小,因此若是隻須要讀取索引,mysql就會極大的減小數據訪問量
  • 由於索引是按照列值順序存儲(至少在單個頁內是如此),因此對於I/O密集型的範圍查詢會比隨機從磁盤讀取每一行數據的I/O要少的多
  • 一些存儲引擎如MyISAM在內存中只緩存索引,數據則依賴於操做系統來緩存,所以要訪問數據須要一次系統調用
  • 因爲InnoDB的聚簇索引,覆蓋索引對InnoDB表特別有用。InnoDB的二級索引在葉子結點中保存了行的主鍵值,因此若是二級主鍵可以覆蓋查詢,則能夠避免對主鍵索引的二次查詢

不是全部類型的索引均可以成爲覆蓋索引,覆蓋索引必需要存儲索引列的值,而哈希索引、空間索引和全文索引等都不存儲索引列的值,因此mysql只能使用B-Tree索引作覆蓋索引。另外,不一樣的存儲引擎實現覆蓋索引的方式也不一樣,並且不是全部的引擎都支持覆蓋索引。 

當發起一個被索引覆蓋的查詢時,在EXPLAINExtra列能夠看到Using index信息,示例以下,KEY last_name (first_name) USING BTREE

mysql> EXPLAIN SELECT * FROM people WHERE first_name = 'm' AND last_name LIKE '%zha%'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: people type: ref possible_keys: last_name key: last_name key_len: 152 ref: const rows: 2 Extra: Using index condition; Using where 1 row in set (0.00 sec) 

在first_name、last_name列上添加一個索引KEY last_name(first_name,last_name) USING BTREE,查詢以下所示:

mysql> EXPLAIN SELECT * FROM people WHERE first_name = 'm' AND last_name LIKE '%zha%'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: people type: ref possible_keys: last_name key: last_name key_len: 152 ref: const rows: 2 Extra: Using index condition 1 row in set (0.00 sec) 

在大多數存儲引擎中,覆蓋索引只能覆蓋那些只訪問索引中部分列的查詢,不過能夠更進一步優化InnoDB。InnoDB的二級索引的葉子結點都包含了主鍵的值,這意味着InnoDB的二級索引能夠有效的利用這些「額外」的主鍵列來覆蓋查詢,示例以下,KEY last_name(last_name) USING BTREE

mysql> EXPLAIN SELECT first_name,last_name FROM people WHERE last_name LIKE 'zha %'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: people type: range possible_keys: last_name key: last_name key_len: 152 ref: NULL rows: 2 Extra: Using index condition 1 row in set (0.00 sec) 

雖然上述示例中索引的列不包含first_name,但也可以用於對first_name作覆蓋查詢。






39:
使用索引優化查詢
  使用索引掃描來優化排序,經過排序操做,按着索引順序掃描數據

注意事項:
一、索引的列順序和order by子句的順序徹底一致
二、索引中全部列的方向(升序,降序)和order by子句徹底同樣
三、order by中的字段所有在關聯表中的第一張表中

利用索引優化🔐
一、索引能夠減小鎖定的行數
二、索引以加快處理速度,同事也加快了鎖的釋放

40:

使用索引掃描作排序

mysql有兩種方式能夠生成有序的結果:經過排序操做,或者按索引順序掃描。若是EXPLAIN中的type列的值爲index,則代表mysql使用了索引掃描來作排序。 

掃描索引自己是很快的,由於只須要從一條索引記錄移動到緊接着的下一條記錄。但若是索引不能覆蓋查詢所需的所有列,那就不得不每掃描一條索引記錄就都回表查詢一次對應的行。這基本上都是隨機I/O,所以按索引順序讀取數據的速度一般要比順序的全表掃描慢,尤爲是在I/O密集型的工做負載時。 

mysql可使用同一個索引既知足排序,又用於查找行,設計索引時應該儘量的同時知足這兩種任務。 

只有當索引的列順序和ORDER BY子句的順序徹底一致,而且全部列的排序方向都同樣時,mysql才能使用索引來對結果作排序若是查詢須要關聯多張表,則只有當ORDER BY子句引用的字段所有爲第一個表時,才能使用索引作排序。ORDER BY子句和查找型查詢的限制是同樣的:須要知足索引的最左前綴的要求,不然,mysql都須要執行排序操做,而沒法利用索引排序。 

有一種狀況下ORDER BY子句能夠不知足索引的最左前綴的要求,就是前導列爲常量的時候,示例以下,KEY last_name (first_name,last_name) USING BTREE

mysql> EXPLAIN SELECT dob,address FROM people WHERE first_name = 'm' ORDER BY last_name\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: people type: ref possible_keys: last_name key: last_name key_len: 152 ref: const rows: 2 Extra: Using index condition; Using where 1 row in set (0.00 sec) 

即時ORDER BY子句不知足索引的最左前綴的要求,也能夠用於查詢排序,這是由於索引的第一列被指定爲一個常數。

冗餘和重複索引

mysql容許在相同列上建立多個索引。重複索引是指在相同的列上按照相同的順序建立的相同類型的索引,應該避免。冗餘索引和重複索引有些不一樣,若是建立了索引(A, B),再建立索引(A)就是冗餘索引,由於這只是前一個索引的前綴索引。 

mysql的惟一限制和主鍵限制都是經過索引實現。 

大多數狀況下都不須要冗餘索引,應該儘可能擴展已有的索引而不是建立新索引。但也有時候出於性能方面的考慮須要冗餘索引,由於擴展已有的索引會致使其變的太大,從而影響其餘使用該索引的查詢的性能。 

通常來講,增長新索引將會致使INSERTUPDATEDELETE等操做的速度變慢,特別是當新增索引後致使達到了內存瓶頸的時候。

若是判斷索引是重複仍是冗餘,使用工具pt-duplicate-key-checker 
關於該工具的使用見pt-duplicate-key-checker檢查數據庫的重複索引

2.查詢未被使用的索引:經過sql語句來查詢 
這裏寫圖片描述

3.更新索引統計信息及減小索引碎片

analyze table table_name
# 維護表的碎片 optimize table table_name #使用不當會致使鎖表

索引和鎖

索引可讓查詢鎖定更少的行。若是查詢從不訪問那些不須要的行,那麼就會鎖定更少的行,從兩個方面來看這對性能都有好處:

  • 首先,雖然InnoDB的行鎖效率很高,內存使用也不多,可是鎖定行的時候仍然會帶來額外開銷
  • 其次,鎖定超過須要的行會增長鎖爭用並減小併發性

在mysql 5.1和更新的版本中,InnoDB能夠在服務器端過濾掉行後就釋放鎖,可是在早起的mysql版本中,InnoDB只有在事務提交後才能釋放鎖。 

InnoDB在二級索引上使用共享鎖(讀鎖),但訪問主鍵索引須要排他鎖(寫鎖)。這消除了使用覆蓋索引的可能性,而且使得SELECT ... FOR UPDATE比LOCK IN SHARE MODE或非鎖定查詢要慢的多

 

 

41 :mysql  拓撲復制

一主多從複製特色

配置簡單
能夠作讀寫分離
多太從庫能夠作讀負載均衡
爲不一樣的業務使用不一樣的從庫
將一個備庫放到遠程數據中心,用做災難恢復

 

42:mha高可用過程

流程以下:

  • 從宕機崩潰的master保存二進制日誌事件(binlog events)。
  • 識別含有最新更新的slave。
  • 應用差別的中繼日誌(relay log)到其它slave。
  • 應用從master保存的二進制日誌事件(binlog events)。
  • 提高一個slave爲新master並記錄binlog file和position。
  • 使其它的slave鏈接新的master進行復制。
  • 完成切換manager主進程OFFLINE
43:讀寫分離實現方案
 

應用層解決
優勢:

一、多數據源切換方便,由程序自動完成;

二、不須要引入中間件;

三、理論上支持任何數據庫;

缺點:

一、由程序員完成,運維參與不到;

二、不能作到動態增長數據源;
中間件解決(maxscale)
優勢:

一、源程序不須要作任何改動就能夠實現讀寫分離;

二、動態添加數據源不須要重啓程序;

缺點:

一、程序依賴於中間件,會致使切換數據庫變得困難;

二、由中間件作了中轉代理,性能有所降低;
3:對延遲要求很高的沒法自動切換爲主庫

44:

相關文章
相關標籤/搜索