MySQL

MySQL 在過去由於高效能、低成本、可靠,已經成為最流行的開源資料庫,因此被廣泛地應用在 Internet 上的中小型網站中。非常流行的開源軟體組合 LAMP 中的「M」指的就是 MySQL。

MariaDB 資料庫管理系統是 MySQL 的一個分支,主要由開源社群在維護,採用 GPL 授權許可。開發這個分支的原因是因為甲骨文公司收購了 MySQL 後,有將 MySQL 閉源的潛在風險,因此社群採用分支的方式來避開這個風險。MariaDB 的目的是完全相容 MySQL,包括 API 和命令列,使之能輕鬆成為 MySQL 的代替品。

MariaDB 和 MySQL 全面对比:
https://www.infoq.cn/article/mariadb-vs-mysql

MariaDB 的文档中列出了 MySQL 和 MariaDB 之间的数百个不兼容问题。因此,我们无法通过简单的方案在这两个数据库之间进行迁移。

大多数数据库管理员都希望 MariaDB 只是作为 MySQL 的一个 branch,这样就可以轻松地在两者之间进行迁移。但从最新发布的几个版本来看,这种想法是不现实的。MariaDB 实际上是 MySQL 的一个 fork,这意味着在它们之间进行迁移需要考虑很多东西。

大多数 MariaDB 版本允许你从 MySQL 复制数据,这意味着你可以轻松地将 MySQL 迁移到 MariaDB。但反过来却没有那么容易,因为大多数 MySQL 版本都不允许从 MariaDB 复制数据。

此外,值得注意的是,MySQL GTID 不同于 MariaDB GTID,所以将数据从 MySQL 复制到 MariaDB 后,GTID 数据将相应地做出调整。

GTID 原理介绍
https://blog.51cto.com/sumongodb/2090307

GTID又叫全局事务ID(Global Transaction ID),是一个已提交事务的编号,并且是一个全局唯一的编号。MySQL5.6版本之后在主从复制类型上新增了GTID复制。

GTID是由server_uuid和事务id组成的,即GTID = server_uuid:transaction_id。 server_uuid是在数据库启动过程中自动生成的,每台机器的server-uuid不一样。uuid存放在数据目录的auto.cnf文件下。而transaction_id就是事务提交时由系统顺序分配的一个不会重复的序列号。

(1)GTID使用master_auto_position=1代替了基于binlog和position号的主从复制搭建方式,更便于主从复制的搭建。

(2)GTID可以知道事务在最开始是在哪个实例上提交的。

(3)GTID方便实现主从之间的failover,再也不用不断地去找position和binlog 了。




MySQL 儲存引擎

MySQL 8 以後,加強了 InnoDB ,不再需要 MyISAM 這種儲存引擎。

InnoDB 這種儲存引擎所提供的功能如同商用資料庫軟體,像是交易 (transaction)、紀錄鎖定 (row-level locking) 與自動回復 (auto-recovery)。

而 MEMORY 這一個儲存引擎,雖然它把資料儲存在紀憶體中,所以運作效率是 MySQL 中最快的,但當人們之所以會考慮到快取功能,不僅僅是為了快,往往也為了減輕 MySQL 負擔,MEMORY 引擎仍然無法避免調用時需要驗證 MySQL 權限;因此,當需要使用快取方案時,直接使用 Redis 等方案更恰當。
而需要 SQL 聯表查詢這個優點時,MySQL 統一使用 InnoDB 即可。



http://www.qttc.net/201208175.html

MySQL默認操作模式是 autocommit 模式。這就表示除非顯式地開始一個事務,否則每個查詢都被當做一個單獨的事務自動執行。我們可以通過設置 autocommit 的值改變是否是autocommit 模式。

通過以下命令可以查看當前 autocommit 模式

show variables like 'autocommit';

從查詢結果中,我們發現Value的值是ON,表示 autocommit 開啟。我們可以通過以下SQL語句改變這個模式:

set autocommit = 0;

值0和OFF都是一樣的,當然,1也就表示ON。通過以上設置 autocommit=0,則用戶將一直處於某個事務中,直到執行一條 commit 提交 或 rollback語句才會結束當前事務重新開始一個新的事務。

舉個例子:

張三給李四轉賬500元。那麼在數據庫中應該是以下操作:

1,先查詢張三的賬戶餘額是否足夠

2,張三的賬戶上減去500元

3,李四的賬戶上加上500元

以上三個步驟就可以放在一個事務中執行提交,要么全部執行要么全部不執行,如果一切都OK就commit提交永久性更改數據;如果出錯則rollback回滾到更改前的狀態。利用事務處理就不會出現張三的錢少了李四的賬戶卻沒有增加500元或者張三的錢沒有減去李四的賬戶卻加了500元。

MyISAM 存儲引擎不支持事務處理,所以改變 autocommit 沒有什麼作用,但不會報錯,所以要使用事務處理一定要確定 存儲引擎 是支持事務處理的,如 InnoDB。



● 如何啟動服務、停止服務、更改密碼、登入 MySQL

$ sudo service mysqld status
$ sudo service mysqld stop
$ sudo service mysqld start
$ sudo service mysqld restart
$ sudo mysqladmin -u root -p password (更改密碼)
$ mysql -u root -p (登入)
$ mysql -h 123.123.123.123 -u root -p



从mysql 8.0开始,mysql默认的CHARSET已经不再是Latin1了,改为了utf8mb4(参考链接),并且默认的COLLATE也改为了utf8mb4_0900_ai_ci。

utf8mb4_0900_ai_ci大体上就是unicode的进一步细分,0900指代unicode比较算法的编号( Unicode Collation Algorithm version),ai表示accent insensitive(发音无关),例如e, è, é, ê 和 ë是一视同仁的。

https://bschen.tw/posts/mysql-utf8mb4/ https://juejin.im/post/5bfe5cc36fb9a04a082161c2

https://juejin.im/post/5bfe5cc36fb9a04a082161c2

CREATE TABLE (

……

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

优先级顺序是 SQL语句 > 列级别设置 > 表级别设置 > 库级别设置 > 实例级别设置。

https://bschen.tw/posts/mysql-utf8mb4/

由於 MySQL 8.0 預設的 collation 是 utf8mb4_0900_ai_ci 而不是我們原先以為「最精準」的 utf8mb4_unicode_ci,查了一下,發現:

0900 代表 Unicode Collation Algorithm (UCA) 的 9.0.0 版本,包含在 2016 年發佈的 Unicode 9.0.0 之中3。目前最新的版本是 11.0.04
ai 代表 accent insensitivity,即同一字母的不同標音不影響排序
ci 就是 case insensitivity 了,同一字母的大小寫不影響排序

所以,不管是從其他方面,或是我們所認為的「精準」來說,utf8mb4_0900_ai_ci (UCA 9.0.0) 都比 utf8mb4_unicode_ci (UCA 4.0.0) 要來得好。甚至是在 MySQL 5.7.7 裡,也都有 utf8mb4_unicode_520_ci (UCA 5.2.0) 這個更好的選擇

結論就是,在 MySQL 中,設定 UTF-8 編碼的最佳組合是:

5.5.3+: charset=utf8mb4, collation=utf8mb4_unicode_ci
5.7.7+: charset=utf8mb4, collation=utf8mb4_unicode_520_ci
8.0.0+: charset=utf8mb4, collation=utf8mb4_0900_ai_ci

順便一提,utf8mb4 這個 charset 是在 MySQL 5.5.3 加入的。在此之前,只有 utf8(5.5.3 之後等義於 utf8mb3)可用


● 如何將 MySQL 調整成全 UTF-8 語系

mysql使用utf8mb4经验吐血总结
http://seanlook.com/2016/10/23/mysql-utf8mb4/

 C/C++ 内存空间分配问题

这是我们这边的开发遇到的一个棘手的问题。C或C++连接MySQL使用的是linux系统上的 libmysqlclient 动态库,程序获取到数据之后根据自定义的一个网络协议,按照mysql字段定义的固定字节数来传输数据。从utf8转utf8mb4之后,c++里面针对character单字符内存空间分配,从3个增加到4个,引起异常。

这个问题其实是想说明,使用utf8mb4之后,官方建议尽量用 varchar 代替 char,这样可以减少固定存储空间浪费(关于char与varchar的选择,可参考 这里)。但开发设计表时 varchar 的大小不能随意加大,它虽然是变长的,但客户端在定义变量来获取数据时,是以定义的为准,而非实际长度。按需分配,避免程序使用过多的内存。

MySQL字符数据类型char与varchar的区别
http://seanlook.com/2016/04/28/mysql-char-varchar-set/

varchar善于存储值的长短不一的列,也是用的最多的一种类型,节省磁盘空间。update时varchar列时,如果新数据比原数据大,数据库需要重新开辟空间,这一点会有性能略有损耗,但innodb引擎下查询效率比char高一点。这也是innodb官方推荐的类型。

如果存储时真实长度超过了char或者varchar定义的最大长度呢?

在SQL严格模式下,无论char还是varchar,如果尾部要被截断的是非空格,会提示错误,即插入失败
在SQL非严格模式下,无论char还是varchar,如果尾部要被截断的是非空格,会提示warning,但可以成功
如果尾部要被截断的是空格,无论SQL所处模式,varchar都可以插入成功但提示warning;char也可以插入成功,并且无任何提示
这里特意提到SQL的严格模式,是因为在工作中也遇到过一些坑,参考MySQL的sql_mode严格模式注意点。


[ec2-user ~]$ sudo mysql -u root -p

Enter password:(打上 mysql 的密碼)

Welcome to the MySQL monitor. ...

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> \s

--------------

Connection id:
Current database:
Current user:
SSL:
Current pager:
Using outfile:
Using delimiter:
Server version:
Protocol version:
Connection:
(重點在底下幾行,預設為 Latin1,但是調整好以後就會變成如下的 utf8:)
Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
UNIX socket: /var/lib/mysql/mysql.sock

--------------

由上可知,要將 MySQL 調整成全 UTF8 有幾項參數需要調整。如果上述四項是 Latin1 (為何預設為 Latin1?因為 MySQL 是瑞典人開發的,他們使用的語系為 Latin1,所以 MySQL 預設語系就是 Latin1),該如何調整成 utf8?必須進入 MySQL 的設定檔作修正。

步驟一:修改 MySQL 設定檔。

[ec2-user ~]$ sudo vim /etc/my.cnf

步驟二:將底下內容增加到設定檔內,寫在內容的最後即可。

[client]
default-character-set=utf8

[mysql]
default-character-set=utf8

[mysqld]
collation-server = utf8_unicode_ci
init-connect='SET NAMES utf8'
character-set-server = utf8


步驟三:重啟 MySQL。
[ec2-user ~]$ sudo service mysqld restart


這時 MySQL 已全部修改成 utf8 了,但日後開發比如說 php 程式時,必須在連結 MySQL 時加入以下幾行程式碼,保證程式中用 utf8 傳送:

mysql_query("SET NAMES 'utf8'");
mysql_query("SET CHARACTER_SET_CLIENT='utf8'");
mysql_query("SET CHARACTER_SET_RESULTS='utf8'");

mysql_connect, mysql_query 等方法在 PHP 5.5.0 以後已經停用,取而代之的是 MySQLi 或 PDO_MySQL 等方法。


日後製作新的資料庫時,可以利用以下的 MySQL 指令,設定以及確認資料庫的預設文字碼,例如 "MyDB" 的資料庫的預設文字碼設定為「UTF-8」:

mysql> create database MyDB default character set utf8;
mysql> show create database MyDB;


觀念 ( Character Set 與 Collation ):http://www.codedata.com.tw/database/mysql-tutorial-7-charset-database/


utf8_general_ci  (Unicode) (多語言) (大小寫不相符) (轉換時速度比較快)
utf8_unicode_ci  (Unicode) (多語言) (大小寫不相符) (轉換時比較精準)

何謂轉換?簡單說就是當資料要從一個編碼換成另外一個編碼時,
MySQL 需要在兩個 codepage 裡面找出相對應的字元位置在哪裡。

對 utf8_general_ci 來說,來源 codepage 裡面的一個字元只能對應到目標 codepage 裡面的一個字元,
而 utf8_unicode_ci 則可以把來源 codepage 裡的一個字元對應到目標 codepage 裡的多個字元(或反過來)。

例如德文裡的 ß 要轉換成英文的時候如果是用 utf8_unicode_ci 轉換會變成正確的 ss ,
但是如果用 utf8_general_ci 的話則會變成單一的 s 而已。
所以如果設成 utf8_unicode_ci 就不需要擔心資料會在轉換間遺失了。




utf8mb4 vs utf8

utf8 跟 utf8mb4 具有相同的儲存特性:相同的代碼值,相同的編碼,相同的長度。不過 utf8mb4 擴展到一個字符最多可有 4 位元,所以能支持更多的位元集。 utf8mb4 兼容 utf8,且比 utf8 能表示更多的字串,將編碼改為 utf8mb4 不需要做其他轉換。

為了要跟國際接軌,原本的 utf8 編碼在儲存某些國家的文字 (或是罕見字) 已經不敷使用,
因此在 MySQL 5.5.3 版以上,可以使用 4-Byte UTF-8 Unicode 的編碼方式。

MySQL 支持的 utf8 編碼最大長度為 3 位元 (Unicode 字符是0xffff) 稱之為 Unicode 的基本多文本平面 (BMP),但如果遇到 4 位元的寬字串就會插入異常,也就是任何不在基本多文本平面的 Unicode 字串都無法使用 Mysql 的 utf8 字串集儲存。

如果要開發討論區或是大型跨國網頁程式,為了擁有更佳的文字兼容性,就可以考慮使用 utf8mb4。

然而,在 CHAR 類型數據,utf8mb4 會比 utf8 多消耗一些空間,故 MySQL 官方指出,使用 VARCHAR 替代 CHAR。



● 如何創建新資料庫、賦予使用者權限

mysql> CREATE DATABASE 資料庫名稱;
mysql> GRANT SELECT,INSERT,UPDATE,DELETE ON 資料庫名稱.* TO 使用者 IDENTIFIED BY '使用者密碼';



● 如何備份與復原資料庫

匯出 $ mysqldump -u root -p密碼 資料庫名稱 > /home/ec2-user/sqlbackup/資料庫名稱.sql
壓縮 $ bzip2 /home/ec2-user/sqlbackup/資料庫名稱.sql

只匯出 table
mysqldump -u... -p... mydb t1 t2 t3 > mydb_tables.sql


解壓縮 $ bzip2 -d /home/ec2-user/sqlbackup/名稱.sql.bz2
匯入 $ mysql -u root -p密碼 資料庫名稱 < /home/ec2-user/sqlbackup/名稱.sql

不同版本的 匯入有時候會發生一些狀況,視情況可以用 -f “force” 來忽略導入過程中的錯誤。
$ mysql -u root -p密碼 -f 資料庫名稱 < /home/ec2-user/sqlbackup/資料庫名稱.sql

在 MYSQL 5.6.6 之後,使用上述指令會出現
Warning: Using a password on the command line interface can be insecure.

在 MySQL 5.6.6 之後加入了 mysql_config_editor 這個工具,這個工具將登入資訊存入 /root/.mylogin.cnf,而 .mylogin.cnf 是被加密的。

這裡有一個坑:密碼內不可以有『#』符號,這是一個已知的 bug
https://stackoverflow.com/questions/19372095/mysql-config-editor-login-path-local-not-working

如果真的遇到了,打算要改密碼,在 MySQL 8 以後禁用了許多種改密碼的方法,可以使用

ALTER USER'root'@'localhost'IDENTIFIED BY'新密碼';

https://stackoverflow.com/questions/50691977/how-to-reset-the-root-password-in-mysql-8-0-11



mysql_config_editor 使用方式:
$ mysql_config_editor set --login-path=dbname --host=127.0.0.1 --user=root --password
$ mysql_config_editor print --all
$ mysql --login-path=dbname
更詳細的說明可參考:https://shazi.info/mysql-執行-bash-script-出現-warning-using-a-password-on-the-command-line-interface-can-be-insecure/

所以上述語法配合 mysql_config_editor 這個工具做修正後如下:
$ mysql --login-path=資料庫名稱 資料庫名稱 < /home/ec2-user/sqlbackup/資料庫名稱.sql


如果 MySQL Server 不止一個資料庫,希望可以一次就將所有資料庫備份起來,可以寫一個簡單的 shell script 來執行,又或者使用以下指令:

mysqldump -u root -p密碼 --all-databases > mysql.sql

這個 –all-databases 代表所有資料庫,這樣子 mysqldump 便會將所有資料庫備份到 mysql.sql。


mysqldump 另外加上 --default-character-set=utf8mb4 ,可避免罕見字匯出錯誤。


使用 mysqldump + shell script + rsync + cron 等等可以達到自動備份與異地備份的功能,但備份的時間差依然會有資料損失的風險。

進一步參考文獻:
排程自動備份與異地備份
http://klearmay.pixnet.net/blog/post/22868088
https://www.phpini.com/mysql/mysql-backup-shell-script
http://eugg.blogspot.tw/2013/05/how-to-crontab-mysql-aws-s3.html

鳥哥的 Linux 私房菜:Linux 備份策略
http://linux.vbird.org/linux_basic/0580backup.php

以 rsync 進行同步鏡像備份
http://linux.vbird.org/linux_server/0310telnetssh.php#rsync



備註:

MySQL 原本是一個開放原始碼的關聯式資料庫管理系統,原開發者為瑞典的 MySQL AB 公司,該公司於2008年被昇陽微系統(Sun Microsystems)收購。2009年,甲骨文公司(Oracle)收購昇陽微系統公司,MySQL 成為 Oracle 旗下產品。

隨著 MySQL 的不斷成熟,它也逐漸用於更多大規模網站和應用,比如維基百科、Google 和 Facebook 等網站。

但被甲骨文公司收購後,Oracle 大幅調漲 MySQL 商業版的售價,且甲骨文公司不再支援另一個自由軟體專案 OpenSolaris 的發展,因此導致自由軟體社群對於 Oracle 是否還會持續支援 MySQL 社群版(MySQL 之中唯一的免費版本)有所擔憂,因此原先一些使用 MySQL 的開源軟體逐漸轉向其它的資料庫。例如 MySQL 的創始人麥克爾·維德紐斯以 MySQL 為基礎,成立分支計劃 MariaDB。維基百科已於 2013 年正式宣布將從 MySQL 遷移到 MariaDB 資料庫。

維基百科:https://en.wikipedia.org/wiki/MySQL

SQL 語法的運用透過閱讀書本範例、實際開發實作、上網搜尋等等,熟能生巧。
SQL 語法教學:http://www.1keydata.com/tw/sql/sql.html

MySQL show 的 整理:http://database.51cto.com/art/201005/202213.htm
更多操作 MySQL 常用指令上網搜尋即可輕鬆找到當下需要用到的指令了。



資料庫的長連接與短連接:http://www.cnblogs.com/endige/archive/2012/04/11/2442534.html

長連接主要用於在少數客戶端與服務端的頻繁通信,因為這時候如果用短連接頻繁通信常會發生 Socket 出錯,並且頻繁創建 Socket 連接也是對資源的浪費。

但是對於服務端來說,長連接也會耗費一定的資源,需要專門的線程來負責維護連接狀態。

總之,長連接和短連接的選擇要視情況而定。



各版本的重要異動:

varchar 類型在 5.0.3 以下的版本中的最大長度限制為 255,而在 5.0.3 及以上的版本中,varchar 類型的長度支持達到 65535。

也就是說,在 5.0.3 以下版本中需要使用固定的 TEXT 或 BLOB 格式存放的數據可以在高版本中使用可變長的 varchar 來存放,這樣就能有效的減少資料庫文件的大小。

text 與 char 和 varchar 不同的是,text不可以有默認值,其最大長度是2的16次方-1

1. 經常變化的欄位用 varchar
2. 知道固定長度的用 char
3. 儘量用 varchar
4. 超過 255 字符的只能用 varchar 或者 text
5. 能用 varchar 的地方不用 text

在 CHAR 類型數據,utf8mb4 會比 utf8 多消耗一些空間,故 MySQL 官方指出,使用 utf8mb4 的模式下,用 VARCHAR 替代 CHAR。




程式語言編年史

程式語言編年史原文 下面這張圖片描繪了整個程式語言的歷史。包括各種程式語言的發明人、程式語言的特點和適用領域、被什麼網站或公司使用等 (檢視 完整高清圖 )。 之所以會有那麼多不同的程式語言是因為設計程式語言的初衷不同、對語言學習曲線的追求不同、不同程式之間的執行成本差異...