mysql開發必知必會
mysql的數據庫的數據庫,即存儲mysql數據庫的底層目錄,是在/var/lib/mysql目錄下(Linux,win在目錄下的data中)。
我們新創建的數據庫db1就是在/var/lib/mysql目錄下創建了一個文件夾db1。
mysql相關的目錄
我們使用/usr/bin/mysqladmin創建過root用戶的密碼等操作。
mysql默認的配置文件讀取順序為:
[root@localhost bin]# which mysqld /usr/sbin/mysqld [root@localhost bin]# ^C [root@localhost bin]# /usr/sbin/mysqld --verbose --help |grep -A 1 ‘Default options‘ 2018-03-07 17:30:00 0 [Note] /usr/sbin/mysqld (mysqld 5.6.39) starting as process 14259 ... 2018-03-07 17:30:00 14259 [Note] Plugin ‘FEDERATED‘ is disabled. Default options are read from the following files in the given order: /etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf #mysql的配置信息的讀取目錄順序2018-03-07 17:30:00 14259 [Note] Binlog end 2018-03-07 17:30:00 14259 [Note] Shutting down plugin ‘CSV‘ 2018-03-07 17:30:00 14259 [Note] Shutting down plugin ‘MyISAM‘
查看mysql的字符集
mysql> show variables like ‘character%‘; +--------------------------+----------------------------+ | Variable_name | Value |+--------------------------+----------------------------+ | character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | latin1 | | character_set_filesystem | binary | | character_set_results | utf8 | | character_set_server | latin1 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+ 8 rows in set (0.00 sec) mysql> show variables like ‘%char%‘; +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | latin1 | | character_set_filesystem | binary | | character_set_results | utf8 | | character_set_server | latin1 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+ 8 rows in set (0.00 sec)
此時數據庫的字符集為拉丁,我們需要改為utf8。
修改mysql的默認配置文件/etc/my.cnf。
[mysql] # 設置mysql客戶端默認字符集 default-character-set=utf8 socket=/var/lib/mysql/mysql.sock [mysqld] skip-name-resolve #設置3306端口 port = 3306 socket=/var/lib/mysql/mysql.sock # 設置mysql的安裝目錄 basedir=/usr/local/mysql # 設置mysql數據庫的數據的存放目錄 datadir=/usr/local/mysql/data # 允許最大連接數 max_connections=200 # 服務端使用的字符集默認為8比特編碼的latin1字符集 character-set-server=utf8 # 創建新表時將使用的默認存儲引擎 default-storage-engine=INNODB lower_case_table_name=1 max_allowed_packet=16M
關閉mysql並重新開啟:
[root@localhost mysql-community-server-5.6.39]# service mysqld stop Stopping mysqld (via systemctl): [ 確定 ] [root@localhost mysql-community-server-5.6.39]# service mysqld start Starting mysqld (via systemctl): [ 確定 ] [root@localhost mysql-community-server-5.6.39]# mysql -uroot -p Enter password:
新建數據庫db2顯示db1與db2的數據庫的字符編碼:
mysql> create database db2; Query OK, 1 row affected (0.04 sec) mysql> use db2; Database changed mysql> show variables like ‘%char%‘; +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | utf8 | | character_set_filesystem | binary | | character_set_results | utf8 | | character_set_server | utf8 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+ 8 rows in set (0.00 sec) mysql> use db1; Database changed mysql> show variables like ‘%char%‘; +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | latin1 | | character_set_filesystem | binary | | character_set_results | utf8 | | character_set_server | utf8 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+ 8 rows in set (0.00 sec)
之前創建的數據庫的字符編碼仍為Latin,而修改過後的新建數據庫已經使用utf8了,說明我們的配置生效了。
查看mysql的安裝目錄
[root@localhost mysql-community-server-5.6.39]# vim /etc/my.cnf [root@localhost mysql-community-server-5.6.39]# ps -ef|grep mysql root 14599 1 0 18:44 ? 00:00:00 /bin/sh /usr/bin/mysqld_safe --datadir=/var/lib/mysql --socket=/var/lib/mysql/mysql.sock --pid-file=/var/run/mysqld/mysqld.pid --basedir=/usr --user=mysql mysql 14941 14599 0 18:44 ? 00:00:02 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock --port=3306 root 15008 11441 0 18:54 pts/0 00:00:00 grep --color=auto mysql
mysql主要的配置文件
二進制日誌log-bin 用於主從復制;
錯誤日誌log-error 默認關閉,記錄嚴重警告和錯誤信息。
查詢日誌log 默認關閉,用來查詢sql語句,開啟會降低mysql整體性能
數據文件:前面提到的數據庫的數據庫文件,frm文件用於存放表結構,myd文件存放表數據,myi文件用於存放表索引。
配置文件:Linux為/etc/my.cnf,win為my.ini。
mysql架構介紹
第一層為連接層,connectors。
接下來就進入mysql層:
第二層為一部分是與外層的連接池(並發部分),備份安全集群等部份,然後到對輸入sql語句進行解析的部分(sqlinterface接口對你要進行是curd的某項操作進行分開解析),解析到optimizer部分為mysql自己的邏輯操作部分(人進行數據查詢首先關註select部分,但是機器關心的是從from哪張表開始,這個部分是mysql的優化器),最後一部分是緩存與緩沖,解決數據庫存取時的io操作問題,所以這一層主要是業務邏輯處理層。
第三層為可拔插的存儲引擎部分。有很多種,我們經常使用到的是innodb有時也用myisam。
第四層就是底層的文件存儲層,底層的文件系統等。
與其他數據庫相比,mysql的架構可以在多種不同場景應用並發揮良好作用主要體現在存儲引擎的架構上,可插拔的存儲引擎架構將查詢處理和其他的系統任務以及數據的存儲提取相分離,我們可以根據業務的實際需求選擇合適的存儲引擎。
查看存儲引擎:
mysql> show engines; +--------------------+---------+----------------------------------------------------------------+--------------+------+------------+ | Engine | Support | Comment | Transactions | XA | Savepoints | +--------------------+---------+----------------------------------------------------------------+--------------+------+------------+ | InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES | | CSV | YES | CSV storage engine | NO | NO | NO | | MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO | | BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO | | MyISAM | YES | MyISAM storage engine | NO | NO | NO | | MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO | | ARCHIVE | YES | Archive storage engine | NO | NO | NO | | FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL | | PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO | +--------------------+---------+----------------------------------------------------------------+--------------+------+------------+ 9 rows in set (0.00 sec)
主流的兩種存儲引擎的對比:
關於mysql性能下降的分析
如果mysql的性能下降,sql慢,執行時間長,等待時間長,那麽問題可能出現在:
1.查詢語句寫得太爛了
2.索引失效了
3.關聯查詢的join寫的太多了(可能是表的設計的問題)
4.服務器調優及各個參數的設置問題(緩沖及線程數等)
你寫的sql:
mysql都出來的查詢語句
機讀的順序
mysql索引
定義:索引是幫助mysql高效獲取數據的數據結構。我們可以根據索引的特點理解為,索引就是排好序的快速查找的數據結構。
索引影響的部分是where後面的查找與orderby後面的排序。
除了數據,數據庫系統還維護了一個滿足特定查找算法的數據結構,這些數據結構以某種方式指向數據,這樣就可以在這些數據結構上實現高級查找算法,這種數據結構就是索引。
為了加快col2的查找,可以維護一個二叉樹,每個節點分別包含索引鍵值和一個指向對應數據記錄物理地址的指針,這樣就可以運用二叉查找在一定復雜度內獲取到相應數據,從而快速的檢索出符合條件的記錄。
一般來說,索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲在磁盤上。
我們一般說的索引都是b樹結構組織索引,其中聚集索引,次要索引,覆蓋索引,復合索引,前綴索引,唯一索引都是使用b樹索引。除了b樹索引意外還有hash索引。
索引的優勢:
查找時提高數據檢索效率,降低數據庫io成本。排序時,索引對數據進行排序,降低數據排序成本,降低了CPU的消耗。
索引的劣勢:
索引本身是一張表,保存了主鍵與索引字段,並指向實體表的記錄,所以索引本身也占空間。
索引雖然大大加快了查詢速度,卻降低了更新速度,在更新表時,不僅要存更新的數據,還要存索引文件每次更新添加的索引列字段,都會調整因為更=新帶來的簡直變化後的索引信息。
索引只是提高效率的一個因素,如果你的mysql有大量數據的表,那麽就要花時間研究建立最優秀的索引或優化查詢語句。
mysql索引分類
單值索引:一個索引只包含單個列,一個表可以有多個單列索引。
唯一索引:索引列的值必須唯一,但允許空值。
復合索引:一個索引包含多個列。
b樹查找
這裏磁盤塊Ⅰ存儲了指引搜索方向的數據項,17與35不一定存在於數據表中,只是一個趨勢,葉子節點存的數據必須是真實存在的數據。根節點的數據表示,查找的數據範圍是小於17還是位於17和35之間還是大於35的數據。然後從根出發一直找到索引的數據,只需要三步即可。
那些情況需要創建索引
1.主鍵自動建立唯一索引
2.頻繁作為查找條件的字段應該創建索引
3.查詢中與其他表關聯的字段,外鍵關系建立索引
4.頻繁更新的字段不適合創建索引,不只是更新記錄還會更新索引,加重io負擔
5.where條件裏用不到的字段不創建索引
6.單鍵/組合索引的選擇問題,在高並發下傾向創建組合索引
7.查詢中排序的字段,排序字段通過索引訪問將大大提高排序速度
8.查詢中統計或者分組字段
哪些情況不要創建索引
1.表記錄太少
2.經常增刪改的表
3.數據重復且分布平均的表的字段。比如性別列。
Explain
除了mysql的optimizer自動的優化導致的sql性能下降和cache與buffer的硬件部分性能瓶頸,我們分析一條sql語句是否高效就必須用到Explain進行查詢。
explain關鍵字可以模擬優化sql查詢語句,從而知道mysql是如何處理你的sql語句的,可以用來分析你的查詢語句或是表結構的性能瓶頸。
能查看什麽:
表的讀取順序,數據讀取操作的操作類型,那些索引可以使用,那些索引被實際使用,表之間的引用,每張表有多少行被優化器查詢。
執行方法
explain+sql
explain中的字段
id字段
此字段用來表示mysql查詢時執行select子句或操作表的順序,即表的讀取順序。
查詢結果可能有三種情況
1.id相同時。
即此時mysql加載的順序為t1>t3>t2。
2.id不同
即此時mysql加載的順序為t3>t1>t2。
3.混合存在
即此時mysql加載的順序為t3><derived2>>t2。
select_type字段
即數據讀取操作的操作類型
1.simple
簡單的select查詢,查詢不包括子查詢與union
2.primary
如果查詢包含了任何復雜的字部分,最外層查詢被標記為primary
3.subquery
在select或者where列表中包含了子查詢
4.derived
在from列表包含的子查詢被標記為derived衍生,mysql會遞歸執行這些子查詢,把結果放到臨時表中
5.union
若第二個select出現在union後則被標記為union,若union包含在from子句的子查詢中,外層select將被標記為derived。
6.union result
從union表獲取結果的select
table字段,就是表名字段,表時這一行數據是關於那張表的。
type字段
直接的顯示了表是否被優化是否最佳狀態的直接體現。
一般常見的類型為system>const>eq_ref>ref>range>index>all
當你的數據達到百萬級並且sql語句執行為all,那麽你的查詢語句或者說表需要進行優化了。當你的sql執行為ref或者range就已經很優了。
type的不同狀態:
1.system
表只有一行記錄(等於系統表),是const類型的特例,平時基本遇不到可以忽略不計
2.const常量
表通過索引一次就找到了,const用於比較primary key或者unique索引,因為只匹配一行數據,所以很快
這裏的id為主鍵索引,在t1表唯一只匹配一行數據,查找相當於查詢一個常量。
一張表只有一行數據,相當於京東就你一個用戶,快是快,但是實際基本不會用到。
3.eq_ref
唯一性索引掃描,對於每個索引鍵,表中只有一條記錄與之匹配,常見於主鍵或唯一索引掃描
類比員工表與部門表中,部門表id最為外鍵,員工表的外鍵關聯到部門表id,將部門表id建成索引,ceo作為公司員工,在部門表索引時只能查到一個唯一的數據與之匹配,這種情況就是eq_ref,反之其他的部門擁有多名員工,查詢就是ref。
4.ref字段
非唯一索引掃描,匹配某個單獨值的所有行,可能找到符合條件的多個值,所以它是查找和掃描的混合體。
類比上述的表查找所有的程序員就是ref類型。
5.range
只檢索給定範圍行,使用一個索引來選擇行,key列顯示你使用了哪個索引,一般是where語句出現between,<,>,in等的查詢,這種範圍掃描優於全標搜索,因為他有起始位置。
6.index
全索引掃描,優於all因為只掃描了索引,索引往往小於數據的大小。
7.all
全表查詢,匹配到所有行
possible_keys與key字段
possible_key是smysql判斷你可能使用的索引,顯示可能應用在這張表的索引,一個或多個,查詢涉及到的字段上若存在索引,該索引將被列出,但不一定被查詢實際使用
key字段
實際中使用的索引,如果為null則沒有使用索引
這種情況為查詢中使用了覆蓋索引,該索引與查詢的select重疊。
key_length字段
條件越精確,key_length越長,此字段為索引字段最大可能長度,並非實際使用長度,根據定義計算得出,不是通過表內檢索得來的值。表示索引中使用的字節數,可通過該列計算查詢中使用的索引長度。
ref字段
顯示索引的那一列被使用了,如果可能的話是一個常數,那些列或常量被用於查找索引列上的值。
即ref體現了實際被索引的列。
rows字段
根據表中信息,估算找到所需記錄大致需要讀取的行數。
extra
包含的額外信息,也是重要字段
1.using filesort
說明mysql會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行讀取。
這裏我們對表中的三列進行了聯合索引,前者在orderby排序時使用了外部排序,這大大降低了表的排序性能,因為在使用索引排序時最好是按照它的索引順序進行排序。
2.using temporary
使用了臨時表保存中間結果,mysql在對查詢結果排序時使用了臨時表,常見於排序orderby和分組查詢groupby。
在這張表中,創建col1與col2聯合索引,groupby跳過col1直接groupby col2,導致斷層,需要創建臨時的表,mysql對臨時表進行一次自己的排序。
3.using index
所以這是個好字段,使用覆蓋索引。
還有一些其他字段不很重要的字段,就不一一解釋了,有興趣自行了解。
範圍後的索引會失效
左右連接查表的時候給另一邊加索引。
多表連接查詢時的優化:
1.減少join查詢的循環總次數,即永遠以小結果集驅動大結果集。
2.優先優化nestedloop的內層循環。
3.保證join語句中被驅動表join字段已經被索引
4.無法保證被驅動表的join條件字段被索引且內存資源充足的前提下,不要吝惜joinbuffer的設置。
mysql開發必知必會