聊聊數據庫~5.SQL運維上篇

1.6.SQL運維篇

運維這塊逆天只能說夠用,並不能說擅長,因此這篇就當拋磚之用,歡迎補充和糾錯html

PS:再說明下CentOS優化策略這部分的內容來源:首先這塊逆天不是很擅長,因此主要是參考網上的DBA文章,以後請教了下運維相關的朋友,你們辯證看就好了,我只能保證90%的準確度(具體看業務)mysql

1.6.1.概念

1.RAID系

RAID:磁盤冗餘隊列linux

把多個容量小的磁盤組成一組容量更大的磁盤,並提供數據冗餘來保證數據完整性的技術redis

RAID0:數據條帶(好處:成本低,應用:數據備份)算法

須要硬盤數>=2,數據沒有冗餘或修復功能,只是多個小容量變成大容量的功能sql

RAID1:磁盤鏡像(好處:數據安全、讀很快)shell

磁盤的數據鏡像到另外一個磁盤上,最大限度的保證系統的可靠性和可修復性數據庫

RAID5:分佈式奇偶校驗磁盤陣列(好處:性價比高,缺點:兩塊磁盤失效則整個卷的數據都沒法恢復,應用:從數據庫)django

把數據分散到多個磁盤上,若是任何一個盤數據失效均可以從奇偶校驗塊中重建centos

RAID10:分片鏡像(優勢:讀寫性能良好,相對RAID5重建更簡單速度更快,缺點:貴)

對磁盤先作RAID1以後對兩組RAID1的磁盤再作RAID0

RAID級別 特色 備份 盤數
RAID0 便宜,讀寫快,不安全 沒有 N
RAID1 貴,高速讀,最安全 2N
RAID5 性價比高,讀快,安全 N+1 取決於最慢盤
RAID10 貴,高速,安全 2N

2.SAN和NAS

SAN:經過專用高速網將一個或多個網絡存儲設備和服務器鏈接起來的專用存儲系統

經過光纖鏈接到服務器,設備經過塊接口訪問,服務器能夠將其當作硬盤使用

NAS:鏈接在網絡上, 具有資料存儲功能的裝置,以數據爲中心,將存儲設備與服務器完全分離,集中管理數據,從而釋放帶寬、提升性能、下降總擁有成本、保護投資。其成本遠遠低於使用服務器存儲,而效率卻遠遠高於後者

使用網絡進行鏈接,經過基於文件協議(NFS、SMB)來訪問

PS:網絡存儲通常都是用來搭建開發環境或者數據庫備份

3.QPS和TPS

QPS(Queries Per Second):每秒鐘處理的請求數(通常都是查詢,但DML、DDL也包括)

eg:10ms處理1個sql,1s處理100個sql,那麼QPS<=100100ms處理1個sql,QPS<=10)

TPS(Transactions Per Second):每秒鐘系統可以處理的交易或事務的數量(每秒事務數|消息數

一個事務是指一個客戶機向服務器發送請求而後服務器作出反應的過程。客戶機在發送請求時開始計時,收到服務器響應後結束計時,以此來計算使用的時間和完成的事務個數

PS:QPS看的多些

1.6.2.常見問題

1.超高的CPU|內存使用率:容易因CPU|內存資源耗盡而宕機

PS:若是是CPU密集型:須要更好的CPU;須要更大的併發量:須要更多的CPU(WEB項目)

MySQL有同一數據中屢次寫操做合併爲一次寫操做

2.併發量大:容易致使數據庫鏈接數被佔滿

PS:MySQL的max_connections默認是100(根據硬件條件調整)

3.磁盤IO:致使性能直線降低(熱點數據內存放不下時

解決:按期整理磁盤碎片、RAID加強傳統硬盤SSDFusion-io(PCIe)、網絡存儲NAS or ASN

PS:SSD應用於存在大量隨機IO或解決單線程IO瓶頸的場景

4.網卡流量(網絡):容易出現沒法鏈接數據庫的現象

解決:

  1. 減小從服務器的數量
  2. 分級緩存(防止同一時間緩存的大量失效)
  3. 避免使用select *進行查詢(減小傳輸過程當中的無用字節)
  4. 分離業務網絡和服務器網絡

5.大表定義:單表數據量超過千萬行 or 表數據文件超過10G

問題:大表更容易出現慢查詢、DDL也很慢也容易致使其餘問題
解決:分庫分表(拆分爲多個小表)
PS:分庫分表前能夠對大表的歷史數據進行歸檔(冷熱數據隔離)【核心:歸檔時間點的選擇】

DDL影響的補充說明:

  • 建索引很慢,並且會引發長時間的主從延遲
  • 修改表結構須要長時間鎖表
    • 引發長時間的主從延遲
    • 影響正常的數據操做

分庫分表容易出現的問題:

  1. 分表主鍵的選擇
    • 不能保證id是全局惟一,這時候可使用諸如雪花算法來解決
  2. 跨庫跨表的join問題
  3. 事物問題(分佈式事物誕生了)

PS:不太影響的案例:日誌表insertselect不少,不多delete和update)

6.大事務定義:運行時間較長,操做數據比較多的事物

問題:

  1. 鎖定太多的數據,形成大量的阻塞和鎖超時
  2. 回滾須要的時間很長(又得鎖一段時間了)
  3. 執行時間長,容易致使主從的延遲
    解決:
  4. 避免一次處理大量數據(分批處理)
  5. 去除在事物中沒必要要的select語句(通常都是事物中使用過多查詢致使的)
    • PS:select徹底能夠在事物外查詢,事物專一於寫

SQL標準中定義的4種隔離級別:

  1. 未提交讀(read uncommited
  2. 已提交讀read commited
    • 不可重複讀
  3. 可重複讀repeatable read
    • innodb的默認隔離級別
  4. 可串行化(serializable
  5. PS:隔離性低到高,併發性高到低

PS:查看事物隔離級別-show variables like '%iso%';,設置會話的隔離級別:set session tx_isolation='read-committed'

擴展:CentOS優化策略(MySQL服務器)

1.內核相關(/etc/sysctl.conf

查看默認值:sysctl -a

tcp相關設置:

# 三次握手listen的最大限制
net.core.somaxconn = 65535 # 默認是128

# 當網絡接受速率大於內核處理速率時,容許發送到隊列中的包數
net.core.netdev_max_backlog = 65535 # 默認是1000

# Linux隊列的最大半鏈接數(超過則丟包)
net.ipv4.tcp_max_syn_backlog = 65535 # 默認是128(不適合Web服務器)

PS:這邊只是一個參考,本身能夠根據環境適當下降(最大端口數通常都是65535)

注意:若是是Web服務器,net.ipv4.tcp_max_syn_backlog不宜過大(容易有synflood攻擊的安全問題),net.ipv4.tcp_tw_recyclenet.ipv4.tcp_tw_reuse不建議開啓

加快tcp連接回收的幾個參數:

# TCP等待時間,加快tcp連接回收
net.ipv4.tcp_fin_timeout = 10 # 默認60

# 把發起關閉,但關閉沒完成的TCP關閉掉
net.ipv4.tcp_tw_recycle = 1   # 默認0(不適合Web服務器)

# 容許待關閉的socket創建新的tcp
net.ipv4.tcp_tw_reuse = 1     # 默認0(不適合Web服務器)

PS:net.ipv4.tcp_tw_reuse擴展說明:主動調用closed的一方纔會在接收到對端的ACK後進入time_wait狀態

參考文章:https://blog.csdn.net/weixin_41966991/article/details/81264095

緩存區大小的最大值和默認值:

net.core.wmem_default = 87380 # 默認212992
net.core.wmem_max = 16777216  # 默認212992
net.core.rmem_default = 87380 # 默認212992
net.core.rmem_max = 16777216  # 默認212992

PS:每一個socket都會有一個rmem_default大小的緩存空間(若是設置了setsockopt則就是多少,最大不超過rmem_max

減小失效鏈接所佔用的系統資源

# 對於tcp失效連接佔用系統資源的優化,加快資源回收效率
# 連接有效時間(單位s)
net.ipv4.tcp_keepalive_time = 120 # 默認7200

# tcp未得到相應時重發間隔(單位s)
net.ipv4.tcp_keepalive_intvl = 30 # 默認75

# 重發數量(單位s)
net.ipv4.tcp_keepalive_probes = 3 # 默認9

內存相關參數:

# 共享單個共享內存下的最大值
kernel.shmmax = 4294967295   # 最大爲物理內存-1byte

# 除非虛擬內存所有佔滿,不然不使用交換分區(爲了性能)
# (free -m ==> Swap)
vm.swappiness = 0            # 默認30

PS:kernel.shmmax設置的足夠大,通常就是爲了容納整個innodb的緩衝池

eg:4G = 4*1024 M = 4*1024*1024 KB = 4*1024*1024*1024 byte = 4294967296 - 1 = 4294967295
PS:unsigned int => [0, 2^32) => [0,4294967296) => [0,4294967295] 巧不,同樣的值

2.資源限制(/etc/security/limit.conf

打開文件數的限制(追加到配置後便可)

# [*|%] [soft|hard] [type_item] [value]
* soft nofile 65536
* hard nofile 65535

默認值:ulimit -a

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 3548
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024  《《看這  
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 3548
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

PS:通常來講是夠用了,可是一個遇到大型數據庫可能就不夠看了(多表多庫配置高)

*:全部用戶有效、soft:當前系統生效、hard:系統中所能設置的最大值、nofile:所限制的資源是打開文件的最大數、65536:數值重啓才生效

3.磁盤調度策略(/sys/block/devname/queue/scheduler

如今默認策略就是deadline,因此不用優化了【對數據庫支持很不錯】

PS:經過cat /sys/block/sda/queue/scheduler查看([這個就是設置的值]

noop [deadline] cfq

若是不是能夠經過:echo deadline > /sys/block/sda/queue/scheduler來設置

cfq:會在隊列中插入一些沒必要要的請求,會致使相應時間加長,通常桌面系統用的比較多

noop:實現了一個FIFO隊列,像電梯工做同樣對IO請求進行組織,當有一個新請求到來時會合併到最近請求以後,以此保證請求同一介質(傾向於餓死讀而利於寫)通常閃存設備RAM嵌入式系統用的比較多

deadline:確保了在一個截止時間內去服務請求(可調整)默認讀期限短於寫期限(防止寫操做由於不能被讀而出現餓死的現象)

4.文件系統

Win:NTFS,Linux:EXT3|四、XFS

Linux如今基本上都是選擇XFS,若是是EXT3EXT4還須要設置一下:/etc/fstab慎重

/dev/sda1/ext4 noatime,nodiratime,data=writeback 1 1

PS:noatime表示不記錄訪問時間,nodiratime不記錄目錄的訪問時間(能夠減小一些寫的操做)

不一樣的日誌策略:data=[wtiteback|ordered|journal]

  1. writeback:只有原數據寫入日誌,原數據寫入和數據寫入並非同步的(最快)PS:Innodb有本身的事務日誌,因此是最好的選擇
  2. ordered:只會記錄原數據,但提供了一些一致性的保證,在寫原數據以前會先寫數據,使他們保持一致(比writeback慢但更安全)
  3. journal:提供了原子日誌的一種行爲,在數據寫入到最終位置以前,將記錄到日誌中(最慢,對Innodb來講是沒有必要)

課後拓展:

TPS、併發用戶數、吞吐量關係
https://www.cnblogs.com/zhengah/p/4532156.html

針對Mysql所在linux服務器的系統優化參數
https://blog.csdn.net/qq_40999403/article/details/80666102

網絡優化之net.ipv4.tcp_tw_recycle參數
https://blog.csdn.net/chengm8/article/details/51668992

linux socket 緩存: core rmem_default rmem_max
https://blog.csdn.net/penzchan/article/details/41682411

Linux上的free命令詳解、swap機制
http://www.cnblogs.com/xiaojianblogs/p/6254535.html

磁盤IO太高時的處理辦法
https://www.cnblogs.com/wjoyxt/p/4808024.html

文件系統對性能的影響
https://blog.csdn.net/qq_30353203/article/details/78197870

1.6.3.MySQL配置參數

建議:優先從數據庫設計和SQL優化着手,而後纔是配置優化和存儲引擎的選擇,最後纔是硬件提高

設計案例:列太多不行,關聯太多也不行(10個之內),不恰當的分區表,使用了外鍵

分區表:一個服務器下,邏輯上仍是一個表,物理存儲上分紅了多個表(相似於SQLServer的水平分庫

PS:分庫分表:物理和邏輯上都拆分紅多個表了

以前講環境的時候簡單說了下最基礎的

[mysqld]
# 獨立表空間: 每個表都有一個.frm表描述文件,還有一個.ibd文件
innodb_file_per_table=on
# 不對鏈接進行DNS解析(省時)
skip_name_resolve=on
# 配置sql_mode
sql_mode='strict_trans_tables'

而後說SQL_Mode的時候簡單說了下全局參數會話參數的設置方法:MySQL的SQL_Mode修改小計

  • 全局參數設置:set global 參數名=參數值;
    • 只對新會話有效,重啓後失效
  • 會話參數設置:set [session] 參數名=參數值
    • 只對當前會話有效,其餘會話不影響

這邊繼續說下其餘幾個影響較大的配置參數:(對於開發人員來講,簡單瞭解便可,這個是DBA的事情了

1.安全相關配置

  • expire_logs_days:自動清理binlog
    • PS:通常最少保存7天(具體根據業務來)
  • max_allowed_packet:配置MySQL接收包的大小
    • PS:默認過小。若是配置了主從,須要配置成同樣大(防止丟包)
  • skip_name_resolve:禁用DNS查找(這個咱們以前說過了,主要是提速)
    • PS:若是啓用了,那麼進行用戶受權時,只能經過ip或者ip段或者本機host出現過的域名進行受權
      • *的是沒影響的
  • sysdata_is_now保證sysdate()返回肯定性日期
    • PS:若是主從使用了binlog的statement模式,sysdata的結果會不同,最後致使數據不一致
      • 相似的問題還有不少,eg:獲取最後一次id的時候(last_insert_id()
      • 擴:如今MySQL有了Mixed模式
  • read_only:通常用戶只能讀數據,只有root用戶能夠寫:
    • PS:推薦在從庫中開啓,這樣就只接受從主庫中的寫操做,其它只讀
    • 從庫受權的時候不要授予超級管理員的權限,否則這個參數至關於廢了
  • skip_slave_start禁用從庫(Slave)自動恢復
    • MySQL在重啓後會自動啓用複製,這個能夠禁止
    • PS:不安全的崩潰後,複製過去的數據可能也是不安全的(手動啓動更合適)
  • sql_mode:設置MySQL的SQL模式(這個上次說過,默認是寬鬆的檢測,這邊再補充幾個)
    • strict_trans_tables:對全部支持事物類型的表作嚴格約束
      • 最多見,主要對事物型的存儲引擎生效,其餘的沒效果
      • PS:若是插入數據不符合規範,則中斷當前操做
    • no_engine_subtitution:建表的時候指定不可用存儲引擎會報錯
    • only_full_group_by:檢驗group by語句的合法性
      • 要求在在分組查詢語句中,把全部沒有使用聚合函數的列,列出來
      • eg:select count(url),name from file_records group by url;
        • 使用了name字段,name不是聚合函數,那必須在group by中寫一下
    • ansi_quotes:不容許使用雙引號來包含字符串
      • PS:防止數據庫遷移的時候出錯
    • PS:生存環境下最好不要修改,容易報錯對業務產生影響(嚴格變寬鬆沒事)

PS:通常SQL_Mode是測試環境相對嚴格(strict_trans_tables,only_full_group_by,no_engine_subtitution,ansi_quotes),線上相對寬鬆(strict_trans_tables

補充說下sysdate()now()的區別:(看個案例就懂了)

PS:對於一個語句中調用多個函數中now()返回的值是執行時刻的時間,而sysdate()返回的是調用該函數的時間

MariaDB [(none)]> select sysdate(),sleep(2),sysdate();
+---------------------+----------+---------------------+
| sysdate()        | sleep(2) | sysdate()        |
+---------------------+----------+---------------------+
| 2019-03-28 09:09:29 |     0 | 2019-03-28 09:09:31  |
+---------------------+----------+---------------------+
1 row in set (2.001 sec)

MariaDB [(none)]> select now(),sleep(2),now();
+---------------------+----------+---------------------+
| now()           | sleep(2) | now()          |
+---------------------+----------+---------------------+
| 2019-03-28 09:09:33 |     0 | 2019-03-28 09:09:33  |
+---------------------+----------+---------------------+
1 row in set (2.000 sec)

2.內存相關

  • sort_buffer_size:每一個會話使用的排序緩衝區大小
    • PS:每一個鏈接都分配這麼多eg:1M,100個鏈接==>100M(默認是所有)
  • join_buffer_size:每一個會話使用的錶鏈接緩衝區大小
    • PS:給每一個join的表都分配這麼大,eg:1M,join了10個表==>10M
  • binlog_cache_size:每一個會話未提交事物的緩衝區大小
  • read_rnd_buffer_size:設置索引緩衝區大小
  • read_buffer_size:對MyISAM全表掃描時緩衝池大小(通常都是4k的倍數)
    • PS:對臨時表操做的時候可能會用到

read_buffer_size的擴充說明:

如今基本上都是Innodb存儲引擎了,大部分的MyISAM的配置就不用管了,可是這個仍是須要配置下的

引入下臨時表知識擴展

  1. 系統使用臨時表:
    • 不超過16M:系統會使用Memory
    • 超過限制:使用MyISAM
  2. 本身建的臨時表:(可使用任意存儲引擎)
    • create temporary table tb_name(列名 類型 類型修飾符,...)

PS:如今知道爲啥配置read_buffer_size了吧(系統使用臨時表的時候,可能會使用MyISAM

3.IO相關參數

主要看看InnodbIO相關配置

事物日誌:(總大小:Innodb_log_file_size * Innodb_log_files_in_group

  • 事物日誌大小:Innodb_log_file_size
  • 事物日誌個數:Innodb_log_files_in_group

日誌緩衝區大小:Innodb_log_buffer_size

通常日誌先寫到緩衝區中,再刷新到磁盤(通常32M~128M就夠了)

知識擴展:redo Log內存中緩衝區的大小:(字節爲單位)

  • show variables like 'innodb_log_buffer_size';
    • PS:以字節爲單位,每隔1s就會把數據存儲到磁盤上
  • show variables like 'innodb_log_files_in_group';
    • PS:有幾個就產生幾個ib_logfile文件(默認是2)

日誌刷新頻率:Innodb_flush_log_at_trx_commit

  • 0:每秒進行一第二天志寫入緩存,並刷新日誌到磁盤(最多丟失1s)
  • 1:每次交執事物就把日誌寫入緩存,並刷新日誌到磁盤(默認
  • 2:每次事物提交就把日誌寫入緩存,每秒刷新日誌到磁盤(推薦

刷新方式:Innodb_flush_method=O_DIRECT

關閉操做系統緩存(避免了操做系統和Innodb雙重緩存)

如何使用表空間:Innodb_file_per_table=1

爲每一個innodb創建一個單獨的表空間(這個基本上已經成爲通用配置了)

是否使用雙寫緩存:Innodb_doublewrite=1(避免發生頁數據損壞)

  • 默認是開啓的,若是出現寫瓶頸或者不在乎一些數據丟失能夠不開啓(開啓後性能↑↑)
  • 查看是否開啓:show variables like '%double%';

設置innodb緩衝池大小:innodb_buffer_pool_size

若是都是innodb存儲引擎,這個參數的設置能夠這樣來算:(通常都是內存的75%
查看命令:show global variables like 'innodb_buffer_pool_size';
PS:緩存數據和索引(直接決定了innodb性能) 課後拓展:http://www.javashuo.com/article/p-ptvyxueu-k.html

innodb緩存池實例的個數:innodb_buffer_pool_instances

PS:主要目的爲了減小資源鎖增長併發。每一個實例的大小=總大小/實例的個數
通常來講,每一個實例大小不能小於1G,並且個數不超過8個

4.其餘服務器參數

  • sync_binlog:控制MySQL如何像磁盤中刷新binlog
    • 默認是0,MySQL不會主動把緩存存儲到磁盤,而是靠操做系統
    • PS:爲了數據安全,建議主庫設置爲1(效率也容易下降)
      • 仍是那句話:通常不去管,具體看業務
  • 控制內存臨時表大小:tmp_table_size and max_heap_table_size
    • PS:建議保持兩個參數一致
  • max_connections:設置最大鏈接數
    • 默認是100,能夠根據環境調節,太大可能會致使內存溢出
  • Sleep等待時間:通常設置爲相同值(經過鏈接參數區分是不是交互鏈接)
    • interactive_timeout:設置交互鏈接的timeout時間
    • wait_timeout:設置非交互鏈接的timeout時間

擴展工具:pt-config-diff

使用參考:pt-config-diff u=root,p=pass,h=localhost /etc/my.conf

eg:比較配置文件和服務器配置

pt-config-diff /etc/my.cnf  h=localhost --user=root --password=pass
3 config differences
Variable                  /etc/my.cnf mariadb2
========================= =========== ========
max_connect_errors        2           100
rpl_semi_sync_master_e... 1           OFF
server_id                 101         102

課後拓展:https://www.cndba.cn/leo1990/article/2789


擴展:常見存儲引擎

常見存儲引擎:

  1. MyISAM:不支持事物,表級鎖
    • 索引存儲在內存中,數據放入磁盤
    • 文件後綴:frm、MYD、MYI
  2. Innodb:事物級存儲引擎,支持行級鎖和事物ACID特性
    • 同時在內存中緩存索引和數據
    • 文件後綴:frm、ibd
  3. Memory:表結構保存在磁盤文件中,表內容存儲在內存中
    • Hash索引、B-Tree索引
    • PS:容易丟失數據(重啓後數據丟失,表結構依舊存在)
  4. CSV:通常都是做爲中間表
    • 以文本方式存儲在文件中,不適合大表
    • frm(表結構)、CSV(表內容)、CSM(元數據,eg:表狀態、數據量)
    • PS:不支持索引(engine=csv),全部列不能爲Null
    • 詳細能夠查看上次寫的文章:小計:協同辦公衍生出的需求
  5. Archive:數據歸檔(壓縮)
    • 文件:.frm(存儲表結構)、.arz(存儲數據)
    • 只支持insertselect操做
    • 只容許在自增ID列上加上索引
    • 適合場景:日誌類(省空間)
  6. Federated:創建遠程鏈接表(性能不怎樣,默認禁止)
    • 本地不存儲數據(數據所有在遠程服務器上)
    • 本地須要保存表結構和遠程服務器的鏈接信息
    • PS:相似於SQLServer的連接服務器

逆天點評:除非你有100%的理由,不然全選innodb,特別不建議混合使用

Memory存儲引擎

Memory存儲引擎:

  1. 支持HashBTree兩種索引
    • Hash索引:等值查找(默認)
    • Btree索引:範圍查找
      • create index ix_name using btree on tb_name(字段,...)
    • PS:不一樣場景下的不一樣選擇,性能差別很大
  2. 全部字段類型都等同於固定長度,且不支持TextBlog等大字段類型
    • eg:varchar(100)==等價於==> char(100)
  3. 存儲引擎使用表級鎖
    • PS:性能不見得比innodb好
  4. 大小由max_heap_table_size決定(默認16M)
    • PS:若是想存大點,就得改參數(對已經存在的表不生效,須要重建才行)
  5. 經常使用場景(數據易丟失,要保證數據可再生
    • 緩存週期性聚合數據的結果
    • 用於查找或者映射的表(eg:郵編和地區的對應表)
    • 保存數據分析中產生的中間表

PS:如今基本上都是redis了,若是不使用redis的小項目能夠考慮(eg:官網、博客...)


文章拓展:

OLAP、OLTP的介紹和比較
https://www.cnblogs.com/hhandbibi/p/7118740.html

now()與sysdate()
http://blog.itpub.net/22664653/viewspace-752576/
https://stackoverflow.com/questions/24137752/difference-between-now-sysdate-current-date-in-mysql

binlog三種模式的區別(row,statement,mixed)
https://blog.csdn.net/keda8997110/article/details/50895171/

MySQL-重作日誌 redo log -原理
https://www.cnblogs.com/cuisi/p/6525077.html

詳細分析MySQL事務日誌(redo log和undo log)
https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html

innodb_flush_method的性能差別與File I/O
https://blog.csdn.net/melody_mr/article/details/48626685

InnoDB關鍵特性之double write
https://www.cnblogs.com/geaozhang/p/7241744.html

存儲引擎的擴展

1.簡單回顧

上節在最後的時候說了下存儲引擎,這邊簡單回顧下:

存儲引擎 是否支持事物 文字說明
MyISAM 不支持 MySQL5.6之前的默認存儲引擎
CSV 不支持 用CSV格式來存儲數據(通常當中間表)
Archive 不支持 只能查詢和添加數據(通常記錄日誌用)
Memory 不支持 數據只存儲在內存中(容易丟失)
innodb 支持(行級鎖) 如今基本上都使用這個
NDB 支持(行級鎖) MySQL集羣才使用(內存型,數據會持久化一份)

補充說明:

  1. Archive存儲引擎的數據會用zlib壓縮,並且只支持在自增ID上添加索引
  2. NDB存儲引擎的數據存儲在磁盤中(熱數據存儲在內存中),支持Ttree索引和集羣
    • 場景:數據須要徹底同步(這些後面會繼續說的)

2.常見場景

提一個場景:innodb表沒法在線修改表結構的時候怎麼解決?

先看下Innodb不支持在線修改表結構都有哪些狀況:(主要從性能方面考慮)

  1. 第一次建立全文索引和添加空間索引MySQL5.6之前版本不支持)
    • 全文索引create fulltext index name on table(列,...);
    • 空間索引:alter table geom add spatial index(g);
  2. 刪除主鍵或者添加自增列
    • PS:innodb存儲就是按照主鍵進行順序存儲的(這時候須要從新排序)
    • 刪除主鍵:alter table 表名 drop primary key
    • 加自增列:alter table 表名 add column id int auto_increment primary key
  3. 修改列類型、修改表字符集
    • 修改列類型:alter table 表名 modify 列名 類型 類型修飾符
    • 修改字符集:alter table 表名 character set=utf8mb4

PS:DDL不能併發執行(表級鎖)長時間的DDL操做會致使主從不一致

DDL無法進行資源限制,表數據多了容易佔用大量存儲IO空間(空間不夠就容易執行失敗)

3.解決方案

安裝:yum install percona-toolkit or apt-get install percona-toolkit

PS:離線包:https://www.percona.com/downloads/percona-toolkit/LATEST/

命令:pt-online-schema-change 選項 D=數據庫,t=表名,u=用戶名,p=密碼

原理:先建立一個類型修改完的表,而後把舊錶數據copy過去,而後刪除舊錶並重命名新表

查看幫助文檔:pt-online-schema-change --help | more

官方文檔:https://www.percona.com/doc/percona-toolkit/LATEST/pt-online-schema-change.html

PS:通常就--alter--charset用的比較多--execute表明執行)

經常使用:pt-online-schema-change --alter "DDL語句" --execute D=數據庫,t=表名,u=用戶名,p=密碼

eg:添加新列:pt-online-schema-change --alter "add 列名 類型" --execute D=數據庫,t=表名,u=用戶名,p=密碼

知識回顧

  • 添加字段:add
    • alter table tb_name add 列名 數據類型 修飾符 [first | after 列名];
    • PS:SQLServer沒有[first | after 列名]
  • 修改字段:alter、change、modify
    • 修改字段名:alter table tb_name change 舊列名 新列名 類型 類型修飾符
    • 修改字段類型:alter table tb_name modify 列名 類型 類型修飾符
    • 添加默認值:alter table tb_name alter 列名 set default df_value
  • 刪除字段:drop
    • alter table tb_name drop 字段名

4.InnoDB專欄

寫在前面的概念:排它鎖(別名:獨佔鎖、寫鎖)、共享鎖(別名:讀鎖)

4.1.innoDB是如何實現事物的?

事物4大特性:A(原子性)C(一致性)I(隔離性)D(持久性)

innodb事務日誌主要就是redo log(重作日誌)和undo log(回滾日誌)

事物特性 innodb實現方式
原子性(A) 回滾日誌(undo log):用於記錄數據修改前的狀態
一致性(C) 重作日誌(redo log):用於記錄數據修改後的狀態
隔離性(I) 鎖(lock):用於資源隔離(共享鎖 + 排他鎖
持久性(D) 重作日誌(redo log) + 回滾日誌(undo log)

我畫個轉帳案例:

05/05/1.innodb事物實現.png

4.2.innodb操做是否會阻塞操做?

通常狀況下:查詢須要對資源添加共享鎖(讀鎖) | 修改須要對資源添加排它鎖(寫鎖)

是否兼容 寫鎖 讀鎖
寫鎖 不兼容 不兼容
讀鎖 不兼容 兼容

PS:共享鎖和共享鎖之間是能夠共存的(讀的多併發)理論上講讀操做和寫操做應該相互阻塞

innodb看起來卻彷彿打破了這個常規,看個案例:

1.啓動一個事物,可是不提交

03/03/1.1.事物不提交.png

2.在另外一個鏈接中查詢

03/03/1.2.另外一個鏈接查詢的結果是undolog中的記錄.png

PS:理論上獨佔鎖沒提交時是不能讀操做的,innodb作了優化,會查詢undo log(未修改前的數據)中的記錄來提升併發性

3.提交事物後再查詢,這時候就看到更新後的數據了

03/03/1.3.更新了.png

PS:這個就是innodb的MVCC(多版本併發控制)


知識拓展:

【推薦】Mysql的InnoDB事務多版本併發控制如何實現(MVCC)

https://www.cnblogs.com/aspirant/p/6920987.html

https://blog.csdn.net/u013007900/article/details/78641913

https://www.cnblogs.com/dongqingswt/p/3460440.html

https://www.jianshu.com/p/a3d49f7507ff

https://www.jianshu.com/p/a03e15e82121

https://www.jianshu.com/p/5a9c1e487ddd

基於mysql全文索引的深刻理解
https://www.cnblogs.com/dreamworlds/p/5462018.html

【推薦】MySQL中的全文索引(InnoDB存儲引擎)
https://www.jianshu.com/p/645402711dac

innodb的存儲結構
https://www.cnblogs.com/janehoo/p/6202240.html

深刻淺出空間索引:爲何須要空間索引
https://www.cnblogs.com/mafeng/p/7909426.html

常見的空間索引方法
https://blog.csdn.net/Amesteur/article/details/80392679

【推薦】pt-online-schema-change解讀
https://www.cnblogs.com/xiaoyanger/p/6043986.html

pt-online-schema-change使用說明、限制與比較
https://www.cnblogs.com/erisen/p/5971416.html

pt-online-schema-change使用注意要點
https://www.jianshu.com/p/84af8b8f040b

詳細分析MySQL事務日誌(redo log和undo log)
https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html

1.6.4.MySQL權限相關

1.帳號權限設置

以前在SQL環境篇的時候簡單提了一下權限設置(點我回顧),如今再說說經常使用的權限知識:

http://www.javashuo.com/article/p-uxkudhsn-dw.html

1.2.建立帳號

用戶組成格式:用戶名@可訪問控制的列表

  1. 用戶名:通常16字節
    • UTF-8爲例:1英文字符 = 1字節,1中文 = 3字節
  2. 可訪問控制列表:
    • %:全部ip均可訪問(通常都這麼幹的,數據比較重要的推薦使用第二種)
    • 192.168.1.%192.168.1網段的ip均可以訪問
      • 這個不包含localhost(數據庫本地服務器不能訪問)
    • localhost:只能經過數據庫服務器進行本地訪問

1.建立命令:create user 用戶名@ip identified by '密碼';

PS:可使用\h create user來查看幫助文檔

05/05/1.createuser.png

2.查看當前用戶:select user();

PS:MariaDB查看當前數據庫有哪些用戶select user,password,host from mysql.user;

MySQL:select user,authentication_string,host from mysql.user;

3.修改密碼:alter user user() identified by '密碼';

4.另類思路:我通常都是直接在表中插入數據(MySQL是authentication_string

eg:insert into mysql.user(user,host,password) values("用戶名","%",password("密碼"));

PS:修改密碼:update mysql.user setpassword=password('新密碼') where user='用戶名';

知識拓展:ERROR 1045 (28000): Access denied for user 'mysql'@'localhost'

1.3.經常使用權限
權限類別 語句 說明文字
admin create user 建立新用戶權限
- grant option 爲用戶設置權限
- super 設置服務器權限
DDL create 建立數據庫和表
- alter 修改表結構權限
- index 建立和刪除索引
- drop 刪除數據庫和表
DML select 查詢表數據權限
- insert 插入表數據權限
- update 刪除表數據權限
- execute 可執行存儲過程
- delete 刪除表數據權限

補充說明:super:如設置全局變量等系統語句,通常DBA會有這個權限

PS:MariaDB查看數據庫支持哪些權限:show privileges;

https://mariadb.com/kb/en/library/show-privileges/

1.4.用戶受權

權限這個東西你們都懂,通常都是最小權限

受權命令以下:grant 權限列表 on 數據庫.表 to 用戶名@ip

PS:開發的時候可能爲了省事這麼設置:grant all [privileges] on 數據庫.* to 用戶名@'%';

正規點通常這麼設置:

  • 線上:grant select,insert,update on 數據庫.* to 用戶名@ip
  • 開發:grant select,insert,update,index,alter,create on 數據庫.* to 用戶名@ip段

PS:查看當前用戶權限:show grants for 用戶名;,刷新數據庫權限:flush privileges;

之前能夠在受權的時候直接建立用戶(加一段identified by '密碼'),新版本好像分開了

1.5.權限收回

命令以下:revoke 權限列表 on 數據庫.表 from 用戶名@ip

eg:revoke create,alter,delete from django.* from dnt@'%'(是from而不是on

2.數據庫帳號安全

這個瞭解便可,我也是剛從DBA朋友那邊瞭解到的知識(MySQL8.0),基本上用不到的,簡單羅列下規範:

  1. 只給最小的權限(線上權限基本上都是給最低的(防黑客))
  2. 密碼強度限制(MySQL高版本默認有限制,主要針對MariaDB)
  3. 密碼有期限(謹慎使用,不推薦線上用戶設置有效期)
  4. 歷史密碼不可用(不能重複使用舊密碼)
    • PS:如今用BAT的產品來修改密碼基本上都是不讓使用上次的密碼

設置前三次使用過的密碼不能再使用:create user@'%'identified by '密碼' password history 3;

PS:設置用戶密碼過時:alter user 用戶名@ip password expire;

3.遷移問題

經典問題:如何從一個實例遷移數據庫帳號到另外一個實例?

  • eg:老集羣 > 新集羣

官方文檔:https://www.percona.com/doc/percona-toolkit/LATEST/pt-show-grants.html

3.1.版本相同

數據庫備份下,而後在新環境中恢復

而後導出用戶建立和受權語句:eg:pt-show-grants -u=root,-p=密碼,-h=服務器地址 -P=3306

擴展文章:pt-show-grants的使用(eg:pt-show-grants --host=192.168.36.123 --port=3306 --user=root --password=密碼

生成的腳本大體是這樣的:(把腳本放新服務器中執行便可)

CREATE USER IF NOT EXISTS 'mysql.sys'@'localhost';
ALTER USER 'mysql.sys'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE' REQUIRE NONE 
PASSWORD EXPIRE DEFAULT ACCOUNT LOCK;GRANT SELECT ON `sys`.`sys_config` TO 'mysql.sys'@'localhost';
GRANT TRIGGER ON `sys`.* TO 'mysql.sys'@'localhost';
GRANT USAGE ON *.* TO 'mysql.sys'@'localhost';
-- Grants for 'root'@'%'
CREATE USER IF NOT EXISTS 'root'@'%';
ALTER USER 'root'@'%' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPI
RE DEFAULT ACCOUNT UNLOCK;GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
3.2.版本不一樣

可使用上面的方法,可是須要使用mysql_upgrade升級下系統表(適用:低版本到高版本)可是推薦使用生成SQL腳本

擴展文章:mysql升級小結和mysql_upgrade的用途

相關文章
相關標籤/搜索