學習 MySQL 需要知道的 28 個小技巧

程序猿凱撒 發佈 2022-07-29T06:20:37.524944+00:00

前言隨著信息技術的不斷發展以及網際網路行業的高速增長,作為開源資料庫的MySQL得到了廣泛的應用和發展。目前MySQL已成為關係型資料庫領域中非常重要的一員。

前言

隨著信息技術的不斷發展以及網際網路行業的高速增長,作為開源資料庫的MySQL得到了廣泛的應用和發展。目前MySQL已成為關係型資料庫領域中非常重要的一員。

無論是運維、開發、測試,還是架構師,資料庫技術都是一個 必備加薪神器,那麼,一直說學習資料庫、學 MySQL,到底是要學習它的哪些東西呢?

一、如何快速掌握 MySQL?

培養興趣

興趣是最好的老師,不論學習什麼知識,興趣都可以極大地提高學習效率。不管學習 MySQL5.7 還是 MySQL8.0 都不例外!

夯實 SQL 基礎

計算機領域的技術非常強調基礎,剛開始學習可能還認識不到這一點。隨著技術應用的深 入,只有有著紮實的基礎功底,才能在技術的道路上走得更快、更遠。對於 MySQL 的學習來說, SQL 語句 是其中最為基礎的部分,很多操作都是通過 SQL 語句來實現的。所以在學習的過程中, 讀者要多編寫 SQL 語句,對於同一個功能,使用不同的實現語句來完成,從而深刻理解其不同之處。

萬字長文詳解資料庫 SQL 開發入門教程

及時學習新知識

正確、有效地利用搜尋引擎,可以搜索到很多關於 MySQL 的相關知識。同時,參考別 人解決問題的思路,也可以吸取別人的經驗,及時獲取最新的技術資料。

多實踐操作

資料庫系統具有極強的操作性,需要多動手上機操作。在實際操作的過程中才能發現問題, 並思考解決問題的方法和思路,只有這樣才能提高實戰的操作能力。

二、技巧分享

下面分享學習 mysql 的 28 個不得不知道的小技巧!

1、MySQL 中如何使用特殊字符?

諸如單引號 ',雙引號 ",反斜線 \ 等符號,這些符號在 MySQL 中不能直接輸入使用,否則會產生意料之外的結果。

舉例:

假設 Lucifer 表中需要存入一行記錄,值為 lucifer's dog,其中的單引號 ' 號,如果不做轉義,則無法成功執行:

mysql> create table lucifer (id int,name char(100));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into lucifer values (1,'lucifer's dog');
    '> 
    '> mysql> 

^C
mysql>

在 MySQL 中,這些特殊字符稱為轉義字符,在輸入時需要以反斜線符號 \ 開頭,所以在使用單引號和雙引號時應分別輸入 \' 或者 \",輸入反斜線時應該輸入 \\,其他特殊字符還有回車符 \r,換行符 \n,制表符 \tab,退格符 \b 等。

mysql> create table lucifer (id int,name char(100));
Query OK, 0 rows affected (0.03 sec)

mysql> insert into lucifer values (1,'lucifer\'s dog');
Query OK, 1 row affected (0.00 sec)

mysql> select * from lucifer;
+------+---------------+
| id   | name          |
+------+---------------+
|    1 | lucifer's dog |
+------+---------------+
1 row in set (0.00 sec)
mysql> 

注意: 在向資料庫中插入這些特殊字符時,一定要進行轉義處理。

2、MySQL 中可以存儲文件嗎?

答案當然是可以的!

MySQL 中的 BLOBTEXT 欄位類型可以存儲數據量較大的文件,可以使用這些數據類型 存儲圖像、聲音或者是大容量的文本內容,例如網頁或者文檔。

mysql> create table view(id int unsigned NOT NULL AUTO_INCREMENT, catid int,title varchar(256),picture MEDIUMBLOB, content TEXT,PRIMARY KEY (id));
Query OK, 0 rows affected (0.03 sec)

mysql> show fields from view;
+---------+--------------+------+-----+---------+----------------+
| Field   | Type         | Null | Key | Default | Extra          |
+---------+--------------+------+-----+---------+----------------+
| id      | int unsigned | NO   | PRI | NULL    | auto_increment |
| catid   | int          | YES  |     | NULL    |                |
| title   | varchar(256) | YES  |     | NULL    |                |
| picture | mediumblob   | YES  |     | NULL    |                |
| content | text         | YES  |     | NULL    |                |
+---------+--------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

mysql> 

雖然使用 BLOB 或者 TEXT 可 以存儲大容量的數據,但是對這些欄位的處理會降低資料庫的性能。

注意: 如果並非必要,可以選擇只儲存文件的路徑。

3、MySQL 中如何執行區分大小寫的字符串比較?

MySQL 是 不區分大小寫 的,因此字符串比較函數也不區分大小寫。

mysql> select 'TRUE' from dual where 'DOG' = 'dog';
+------+
| TRUE |
+------+
| TRUE |
+------+
1 row in set (0.00 sec)

如果想執行區分大小寫的比較,可以在字符串前面添加 BINARY 關鍵字。

mysql> select 'TRUE' from dual where BINARY'DOG' = 'dog';
Empty set (0.00 sec)

mysql> 

例如默認情況下,』DOG『=』dog『 返回結果為 TRUE,如果使用 BINARY 關鍵字,BINARY』DOG』=『dog』 結果為 FALSE,在區分大小寫的情況下,』DOG』 與 』dog』 並不相同。

4、如何從日期時間值中獲取年、月、日等部分日期或時間值?

MySQL 中,日期時間值以字符串形式存儲在數據表中,因此可以使用字符串函數分別截取日期時間值的不同部分。

mysql> create table lucifer(date date);
Query OK, 0 rows affected (0.04 sec)

mysql> show fields from lucifer;
+-------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------+------+-----+---------+-------+
| date  | date | YES  |     | NULL    |       |
+-------+------+------+-----+---------+-------+
1 row in set (0.00 sec)

mysql> insert into lucifer values (now());
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select * from lucifer;
+------------+
| date       |
+------------+
| 2021-11-25 |
+------------+
1 row in set (0.00 sec)

例如某個名稱為 date 的欄位有值 2021-11-25,如果只需要獲得年值,可以輸入 LEFT(date, 4),這樣就獲得了字符串左邊開始長度為 4 的子字符串,即 YEAR 部分的值;

mysql> select LEFT(date, 4) from lucifer;
+---------------+
| LEFT(date, 4) |
+---------------+
| 2021          |
+---------------+
1 row in set (0.00 sec)

如果要獲取月份值,可以輸入 MID(date,6,2),字符串第 6 個字符開始,長度為 2 的子字符串正好為 date 中的月份值。同理,讀者可以根據其他日期和時間的位置,計算並獲取相應的值。

mysql> select MID(date,6,2) from lucifer;
+---------------+
| MID(date,6,2) |
+---------------+
| 11            |
+---------------+
1 row in set (0.00 sec)

5、如何改變默認的字符集?

CONVERT() 函數改變指定字符串的默認字符集!

MySQL 的安裝和配置過程中,其中的一個步驟是可以選擇 MySQL 的默認字符集。但是,如果只改變字符集,沒有必要把配置過程重新執行一遍,在這裡,一個簡單的方式是 修改配置文件

讀者可以在修改字符集時使用 SHOW VARIABLES LIKE 'character_set_%'; 或者 status 命令查看當前字符集,以進行對比。

mysql> SHOW VARIABLES LIKE 'character_set_%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | utf8mb3                    |
| character_set_filesystem | binary                     |
| character_set_results    | latin1                     |
| character_set_server     | utf8mb4                    |
| character_set_system     | utf8mb3                    |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

mysql> status
--------------
mysql  Ver 8.0.26-0ubuntu0.21.04.3 for Linux on aarch64 ((Ubuntu))

Connection id:          10
Current database:
Current user:           root@localhost
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         8.0.26-0ubuntu0.21.04.3 (Ubuntu)
Protocol version:       10
Connection:             Localhost via UNIX socket
Server characterset:    utf8mb4
Db     characterset:    utf8mb4
Client characterset:    latin1
Conn.  characterset:    latin1
UNIX socket:            /var/run/mysqld/mysqld.sock
Binary data as:         Hexadecimal
Uptime:                 36 min 55 sec

Threads: 2  Questions: 325  Slow queries: 0  Opens: 181  Flush tables: 3  Open tables: 69  Queries per second avg: 0.146
--------------

mysql> 

MySQL 配置文件名稱為 my.cnf,該文件在 MySQL 的安裝目錄下面。修改配置文件中的 default-character-setcharacter-set-server 參數值,將其改為想要的字符集名稱,如 gbk、gb2312、latinl 等,修改完之後重新啟動 MySQL 服務,即可生效。

## 找到 my.cnf 位置
root@modb:~# find /etc -iname my.cnf -print
/etc/alternatives/my.cnf
/etc/mysql/my.cnf

## 修改字符集
在[client ]下面加入
default-character-set=utf8
在[ mysqld ] 下面加
character_set_server=utf8

## 重啟 mysql 生效
service mysql restart

此時,登錄 MySQL 後使用 SHOW VARIABLES LIKE 'character_set_%'; 或者 status 命令查看修改結果!

6、DISTINCT 可以應用於所有的列嗎?

查詢結果中,如果需要對列進行降序排序,可以使用 DESC,這個關鍵字只能對其前面的列 進行降序排列。

mysql> select * from lucifer;
+------+----------+
| id   | name     |
+------+----------+
|    1 | lucifer  |
|    2 | lucifer1 |
|    3 | lucifer2 |
+------+----------+
3 rows in set (0.00 sec)

mysql> select * from lucifer ORDER BY id desc;
+------+----------+
| id   | name     |
+------+----------+
|    3 | lucifer2 |
|    2 | lucifer1 |
|    1 | lucifer  |
+------+----------+
3 rows in set (0.00 sec)

例如,要對多列都進行降序排序,必須要在每一列的列名後面加 DESC 關鍵字。

mysql> select * from lucifer order by id desc,name desc;
+------+----------+
| id   | name     |
+------+----------+
|    3 | lucifer2 |
|    2 | lucifer1 |
|    1 | lucifer  |
+------+----------+
3 rows in set (0.00 sec)

DISTINCT 不同,DISTINCT 不能部分使用。換句話說,DISTINCT 關鍵字應用於所有列而不僅是它後面的第一個指定列。

例如,查詢 2 個欄位 sex,age,如果不同記錄的這 2 個欄位的組合值都不同,則所有記錄都會被查詢出來。

mysql> select * from lucifer;
+------+-----------+--------+------+
| id   | name      | sex    | age  |
+------+-----------+--------+------+
|    1 | xiaoli    | male   |   20 |
|    1 | xiaoliu   | female |   21 |
|    1 | xiaozhang | female |   21 |
|    1 | xiaowu    | female |   21 |
+------+-----------+--------+------+
4 rows in set (0.00 sec)

mysql> select distinct sex,age from lucifer;
+--------+------+
| sex    | age  |
+--------+------+
| male   |   20 |
| female |   21 |
+--------+------+
2 rows in set (0.00 sec)

mysql> 

7、ORDER BY 可以和 LIMIT 混合使用嗎?

在使用 ORDER BY 子句時,應保證其位於 FROM 子句之後,如果使用 LIMIT,則必須位於 ORDER BY 之後,如果子句順序不正確,MySQL 將產生錯誤消息。

✅ 正確用法:

mysql> select * from lucifer order by age desc limit 2,4;
+------+--------+--------+------+
| id   | name   | sex    | age  |
+------+--------+--------+------+
|    1 | xiaowu | female |   21 |
|    1 | xiaoli | male   |   20 |
+------+--------+--------+------+
2 rows in set (0.00 sec)

❎ 錯誤用法:

mysql> select * from lucifer limit 2,4 order by age desc;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'order by age desc' at line 1
mysql> 

8、什麼時候使用引號?

在查詢的時候,會看到在 WHERE 子句中使用條件,有的值加上了單引號,而有的值未加。

mysql> select * from lucifer where sex = 'female';
+------+-----------+--------+------+
| id   | name      | sex    | age  |
+------+-----------+--------+------+
|    1 | xiaoliu   | female |   21 |
|    1 | xiaozhang | female |   21 |
|    1 | xiaowu    | female |   21 |
+------+-----------+--------+------+
3 rows in set (0.00 sec)

mysql> 

單引號用來限定字符串,如果將值與字符串類型列進行比較,則需要限定引號;而用來與數值進行比較則不需要用引號。

mysql> select * from lucifer where age = 20;
+------+--------+------+------+
| id   | name   | sex  | age  |
+------+--------+------+------+
|    1 | xiaoli | male |   20 |
+------+--------+------+------+
1 row in set (0.00 sec)

mysql> 

9、在 WHERE子句中 AND 和 OR 必須使用圓括號嗎?

任何時候使用具有 ANDOR 操作符的 WHERE 子句,都應該使用圓括號明確操作順序。

mysql> select * from lucifer where (age = 20 or sex = 'female') and name != 'xiaowu';
+------+-----------+--------+------+
| id   | name      | sex    | age  |
+------+-----------+--------+------+
|    1 | xiaoli    | male   |   20 |
|    1 | xiaoliu   | female |   21 |
|    1 | xiaozhang | female |   21 |
+------+-----------+--------+------+
mysql> 3 rows in set (0.00 sec)

如果條件較多,即使能確定計算次序,默認的計算次序也可能會使 SQL 語句不易理解,因此使 用括號明確操作符的次序,是一個好的習慣。

10、更新或者刪除表時必須指定 WHERE子 句嗎?

個人建議所有的 UPDATE 和 DELETE 語句全都在 WHERE 子句中指定條件。

mysql> update lucifer set age = 22 where name = 'xiaoliu';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from lucifer where name = 'xiaoliu';
+------+---------+--------+------+
| id   | name    | sex    | age  |
+------+---------+--------+------+
|    1 | xiaoliu | female |   22 |
+------+---------+--------+------+
1 row in set (0.00 sec)

mysql> 

如果省略 WHERE 子句,則 UPDATE 或 DELETE 將被應用到表中所有的行。

mysql> update lucifer set age = 22;
Query OK, 3 rows affected (0.01 sec)
Rows matched: 4  Changed: 3  Warnings: 0

mysql> select * from lucifer;
+------+-----------+--------+------+
| id   | name      | sex    | age  |
+------+-----------+--------+------+
|    1 | xiaoli    | male   |   22 |
|    1 | xiaoliu   | female |   22 |
|    1 | xiaozhang | female |   22 |
|    1 | xiaowu    | female |   22 |
+------+-----------+--------+------+
4 rows in set (0.00 sec)

mysql> 

因此,除非確實打算更新或者刪除所有記錄,否則要注意使用不帶 WHERE 子句的 UPDATE 或 DELETE 語句。

注意: 建議在對表進行更新和刪除操作之前,使用 SELECT 語句確認需要刪除的記錄,以免造成無法挽回的結果。

11、索引對資料庫性能如此重要,應該如何使用它?

索引的優點:

  • 通過創建唯一索引可以保證資料庫表中每一行數據的唯一性。
  • 可以給所有的 MySQL 列類型設置索引。
  • 可以大大加快數據的查詢速度,這是使用索引最主要的原因。
  • 在實現數據的參考完整性方面可以加速表與表之間的連接。
  • 在使用分組和排序子句進行數據查詢時也可以顯著減少查詢中分組和排序的時間

缺點:

  • 創建和維護索引組要耗費時間,並且隨著數據量的增加所耗費的時間也會增加。
  • 索引需要占磁碟空間,除了數據表占數據空間以外,每一個索引還要占一定的物理空間。如果有大量的索引,索引文件可能比數據文件更快達到最大文件尺寸。
  • 當對表中的數據進行增加、刪除和修改的時候,索引也要動態維護,這樣就降低了數據的維護速度。

使用索引時,需要綜合考慮索引的優點和缺點。

為資料庫選擇正確的索引是一項複雜的任務。如果索引列較少,則需要的磁碟空間和維護開銷 都較少。如果在一個大表上創建了多種組合索引,索引文件也會膨脹很快。

而另一方面,索引較多 可覆蓋更多的查詢。可能需要試驗若干不同的設計,才能找到最有效的索引。可以添加、修改和刪 除索引而不影響資料庫架構或應用程式設計。

因此,應嘗試多個不同的索引從而建立最優的索引。

12、儘量使用短索引(前綴索引)

對字符串類型的欄位進行索引,如果可能應該指定一個前綴長度。

例如,如果有一個 CHAR(255) 的列,如果在前 10 個或 30 個字符內,多數值是惟一的,則不需要對整個列進行索引。

mysql> select * from lucifer;
+------+-----------+--------+------+
| id   | name      | sex    | age  |
+------+-----------+--------+------+
|    1 | xiaoli    | male   |   22 |
|    1 | xiaoliu   | female |   22 |
|    1 | xiaozhang | female |   22 |
|    1 | xiaowu    | female |   22 |
+------+-----------+--------+------+
4 rows in set (0.00 sec)

mysql> create index idx_lucifer_name on lucifer (name(4));
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from lucifer;
+---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table   | Non_unique | Key_name         | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| lucifer |          1 | idx_lucifer_name |            1 | name        | A         |           1 |        4 |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
1 row in set (0.01 sec)

mysql> 

短索引不僅可以提高查詢速度而且可以節省磁碟空間、減少 I/O 操作。

13、MySQL 存儲過程和函數有什麼區別?

在本質上它們都是存儲程序。

函數:

  • 只能通過 return 語句返回單個值或者表對象;
  • 限制比較多,不能用臨時表,只能用表變量,還有一些函數都不可用等等;
  • 可以嵌入在 SQL 語句中使用,可以在 SELECT 語句中作為查詢語句的一個部分調用;

存儲過程:

  • 不允許執行 return,但是可以通過 out 參數返回多個值;
  • 限制相對就比較少;
  • 一般是作為一個獨立的部分來執行;

14、存儲過程中的內容可以改變嗎?

不可以!

目前,MySQL 還不提供對已存在的存儲過程代碼的修改,如果必須要修改存儲過程,必須使用 DROP 語句刪除之後,再重新編寫代碼,或者創建一個新的存儲過程。

不得不說,這方面還是 Oracle 做的比較好。

15、存儲過程中可以調用其他存儲過程嗎?

可以!

存儲過程包含用戶定義的 SQL 語句集合,可以使用 CALL 語句調用存儲過程,當然在存儲過程中也可以使用 CALL 語句調用其他存儲過程,但是不能使用 DROP 語句刪除其他存儲過程。

16、存儲過程的參數不要與數據表中的欄位名相同。

在定義存儲過程參數列表時,應注意把參數名與資料庫表中的欄位名區別開來,否則將出 現無法預期的結果。

17、存儲過程的參數可以使用中文嗎?

一般情況下,可能會出現存儲過程中傳入中文參數的情況,例如某個存儲過程根據用戶的 名字查找該用戶的信息,傳入的參數值可能是中文。這時需要在定義存儲過程的時候,在後面加 上 character set gbk,不然調用存儲過程使用中文參數會出錯,比如定義 userInfo 存儲過程,代碼 如下:

CREATE PROCEDURE useInfo(IN u_name VARCHAR(50) character set gbk, OUT u_age INT)

18、MySQL 中視圖和表的區別以及聯繫是什麼?

兩者的區別:

  • 視圖是已經編譯好的 SQL 語句,是基於 SQL 語句的結果集的可視化的表,而表不是;
  • 視圖沒有實際的物理記錄,而基本表有;
  • 表是內容,視圖是窗口;
  • 表占用物理空間而視圖不占用物理空間,視圖只是邏輯概念的存在,表可以及時對它進行修改,但視圖只能用創建的語句來修改;
  • 視圖是查看數據表的一種方法,可以查詢數據表中某些欄位構成的數據,只是一些SQL 語句的集合。從安全的角度來說,視圖可以防止用戶接觸數據表,因而用戶不知道表結構;
  • 表屬於全局模式中的表,是實表;視圖屬於局部模式的表,是虛表;
  • 視圖的建立和刪除只影響視圖本身,不影響對應的基本表;

兩者的聯繫:

視圖(view)是在基本表之上建立的表,它的結構(即所定義的列)和內容(即所有記錄) 都來自基本表,它依據基本表存在而存在。

一個視圖可以對應一個基本表,也可以對應多個基本表。

視圖是基本表的抽象和在邏輯意義上建立的新關係。

19、使用觸發器時須特別注意!

在使用觸發器的時候需要注意,對於相同的表,相同的事件只能創建一個觸發器。

mysql> create trigger lucifer_tri before insert on lucifer for each row set NEW.id=NEW.id+1;
Query OK, 0 rows affected (0.01 sec)

mysql> 
mysql> 
mysql> select * from lucifer;
+------+-----------+--------+------+
| id   | name      | sex    | age  |
+------+-----------+--------+------+
|    1 | xiaoli    | male   |   22 |
|    1 | xiaoliu   | female |   22 |
|    1 | xiaozhang | female |   22 |
|    1 | xiaowu    | female |   22 |
|    1 | lucifer   | male   |   20 |
|    1 | lucifer   | male   |   20 |
+------+-----------+--------+------+
6 rows in set (0.00 sec)

mysql> insert into lucifer values(1,'lucifer','male',20);
Query OK, 1 row affected (0.00 sec)

mysql> select * from lucifer;
+------+-----------+--------+------+
| id   | name      | sex    | age  |
+------+-----------+--------+------+
|    1 | xiaoli    | male   |   22 |
|    1 | xiaoliu   | female |   22 |
|    1 | xiaozhang | female |   22 |
|    1 | xiaowu    | female |   22 |
|    1 | lucifer   | male   |   20 |
|    1 | lucifer   | male   |   20 |
|    2 | lucifer   | male   |   20 |
+------+-----------+--------+------+
7 rows in set (0.00 sec)

比如對表 lucifer 創建了一個 BEFORE INSERT 觸發器,那麼如果對表 lucifer 再次創建一個 BEFORE INSERT 觸發器,MySQL 將會報錯,此時,只可以在表 lucifer 上創建 AFTER INSERT 或者 BEFORE UPDATE 類型的觸發器。

mysql> create trigger lucifer_tri before insert on lucifer for each row set NEW.id=NEW.id+1;
ERROR 1359 (HY000): Trigger already exists
mysql> 

靈活的運用觸發器將為操作省去很多麻煩。

20、及時刪除不再需要的觸發器

觸發器定義之後,每次執行觸發事件,都會激活觸發器並執行觸發器中的語句。

如果需求發生變化,而觸發器沒有進行相應的改變或者刪除,則觸發器仍然會執行舊的語句,從而會影響新的數據的完整性。

mysql> drop trigger lucifer_tri;
Query OK, 0 rows affected (0.03 sec)

mysql> 

因此,要將不再使用的觸發器及時刪除。

21、應該使用哪種方法創建用戶?(3種方式)

創建用戶有 3 種方法:

  • 使用 CREATE USER 語句創建用戶
  • 在 mysql.user 表中添加用戶
  • 使用 GRANT 語句創建用戶(僅限 MySQL 8 版本以下使用)

一般情況, 最好使用 GRANT 或者 CREATE USER 語句,而不要直接將用戶信息插入 user 表,因為 user 表中存儲了全局級別的權限以及其他的帳戶信息,如果意外破壞了 user 表中的記錄,則可能會對 MySQL 伺服器造成很大影響。

-- 使用 CREATE USER 語句創建用戶
mysql> create user 'lucifer'@'localhost' identified by 'lucifer';
Query OK, 0 rows affected (0.01 sec)

mysql> 

-- 在 mysql.user 表中添加用戶
mysql> select MD5('lucifer');
+----------------------------------+
| MD5('lucifer')                   |
+----------------------------------+
| cae33a0264ead2ddfbc3ea113da66790 |
+----------------------------------+
1 row in set (0.00 sec)

mysql> 
mysql> INSERT INTO mysql.user(Host, User, authentication_string, ssl_cipher, ssuex509_i09_sr, x5ubject) VALUES ('lohoscalt',uci 'lfer MD5('1',lucifer'), '', '',; '')
Query OK, 1 row affected (0.01 sec)

mysql> 

-- 使用 GRANT 語句創建用戶
mysql> GRANT SELECT ON*.* TO 'lucifer2'@localhost IDENTIFIED BY 'lucifer';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IDENTIFIED BY 'lucifer'' at line 1
mysql>

注意: 由於測試使用的是 MySQL 8 版本,已經不支持 GRANT 直接創建用戶,5.7 版本依然是支持的。

22、mysqldump 備份的文件只能在 MySQL 中使用嗎?

邏輯備份工具,適用於所有的存儲引擎,支持溫備、完全備份、部分備份、對於 InnoDB 存儲引擎支持熱備。

mysqldump 備份的文本文件實際是資料庫的一個副本,使用該文件不僅可以在 MySQL 中恢復資料庫,而且通過對該文件的簡單修改,可以使用該文件在 SQL Server 或者 Sybase 等其他資料庫中恢復資料庫。

root@modb:~# mysqldump -uroot -p hr > /root/hr.db
Enter password: 
root@modb:~# 
root@modb:~# ll hr.db 
-rw-r--r-- 1 root root 25327 Nov 26 08:52 hr.db

這在某種程度上實現了資料庫之間的遷移。

23、如何選擇備份工具?

根據備份的方法(是否需要資料庫離線)可以將備份分為:

  • 熱備(Hot Backup)
  • 冷備(Cold Backup)
  • 溫備(Warm Backup)

MySQL 中進行不同方式的備份還要考慮存儲引擎是否支持,如 MyISAM 不支持熱備,支持溫備和冷備。而 InnoDB 支持熱備、溫備和冷備。

一般情況下,我們需要備份的數據分為以下幾種:

  • 表數據
  • 二進位日誌、InnoDB 事務日誌
  • 代碼(存儲過程、存儲函數、觸發器、事件調度器)
  • 伺服器配置文件

下面是幾種常用的備份工具:

  • mysqldump:邏輯備份工具,適用於所有的存儲引擎,支持溫備、完全備份、部分備份、對於 InnoDB 存儲引擎支持熱備。
  • cp、tar 等歸檔複製工具:物理備份工具,適用於所有的存儲引擎、冷備、完全備份、部分備份。
  • lvm2 snapshot:藉助文件系統管理工具進行備份。
  • mysqlhotcopy:名不副實的一個工具,僅支持 MyISAM 存儲引擎。
  • xtrabackup:一款由 percona 提供的非常強大的 InnoDB/XtraDB 熱備工具,支持完全備份、增量備份。

直接複製數據文件是最為直接、快速的備份方法,但缺點是基本上不能實現增量備份。備份時必須確保沒有使用這些表。如果在複製一個表的同時伺服器正在修改它,則複製無效。備份 文件時,最好關閉伺服器,然後重新啟動伺服器。

24、平時應該打開哪些日誌?

日誌既會影響 MySQL 的性能,又會占用大量磁碟空間。因此,如果不必要,應儘可能少地 開啟日誌。

根據不同的使用環境,可以考慮開啟不同的日誌。

例如,在開發環境中優化查詢效率低的語句,可以開啟慢查詢日誌;

開啟慢查詢日誌: 可以讓MySQL記錄下查詢超過指定時間的語句,通過定位分析性能的瓶頸,才能更好的優化資料庫系統的性能。

-- 檢查是否開啟慢查詢
mysql> show variables like 'slow_query%';
+---------------------+------------------------------+
| Variable_name       | Value                        |
+---------------------+------------------------------+
| slow_query_log      | OFF                          |
| slow_query_log_file | /var/lib/mysql/modb-slow.log |
+---------------------+------------------------------+
2 rows in set (0.00 sec)

mysql> show variables like 'long_query_time';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.01 sec)

-- 開啟慢查詢日誌
mysql> set global slow_query_log='ON'; 
Query OK, 0 rows affected (0.00 sec)

-- 設置查詢超過10秒就記錄
mysql> set global long_query_time=10;
Query OK, 0 rows affected (0.00 sec)

-- 再次檢查是否開啟
mysql> show variables like 'slow_query%';
mysql> +---------------------+------------------------------+
| Variable_name       | Value                        |
+---------------------+------------------------------+
| slow_query_log      | ON                           |
| slow_query_log_file | /var/lib/mysql/modb-slow.log |
+---------------------+------------------------------+
2 rows in set (0.00 sec)

如果需要記錄用戶的所有查詢操作,可以開啟通用查詢日誌;

mysql> show variables like 'general_log%';
+------------------+-------------------------+
| Variable_name    | Value                   |
+------------------+-------------------------+
| general_log      | OFF                     |
| general_log_file | /var/lib/mysql/modb.log |
+------------------+-------------------------+
2 rows in set (0.00 sec)

-- 開啟通用查詢日誌
mysql> SET GLOBAL general_log=1; 
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like 'general_log%';
+------------------+-------------------------+
| Variable_name    | Value                   |
+------------------+-------------------------+
| general_log      | ON                      |
| general_log_file | /var/lib/mysql/modb.log |
+------------------+-------------------------+
2 rows in set (0.00 sec)

如果需要記錄數據的變更,可以開啟二進位日誌;錯誤日誌是默認開啟的。

mysql> show variables like 'log_bin%';
+---------------------------------+-----------------------------+
| Variable_name                   | Value                       |
+---------------------------------+-----------------------------+
| log_bin                         | ON                          |
| log_bin_basename                | /var/lib/mysql/binlog       |
| log_bin_index                   | /var/lib/mysql/binlog.index |
| log_bin_trust_function_creators | OFF                         |
| log_bin_use_v1_row_events       | OFF                         |
+---------------------------------+-----------------------------+
5 rows in set (0.00 sec)

mysql> 

25、如何使用二進位日誌?

二進位日誌主要用來記錄數據變更。

如果需要記錄資料庫的變化,可以開啟二進位日誌。基於二進位日誌的特性,不僅可以用來進行數據恢復,還可用於數據複製。

root@modb:/var/lib/mysql# ls binlog*
binlog.000001  binlog.000002  binlog.index
root@modb:/var/lib/mysql# mysqlbinlog binlog.000001 | mysql -u root -p                                            
Enter password: 
root@modb:/var/lib/mysql# 

在資料庫定期備份的 情況下,如果出現數據丟失,可以先用備份恢復大部分數據,然後使用二進位日誌恢復最近備份後變更的數據。在雙機熱備情況下,可以使用 MySQL 的二進位日誌記錄數據的變更,然後將變更部分複製到備份伺服器上。

26、如何使用慢查詢日誌?

慢查詢日誌主要用來記錄查詢時間較長的日誌。

在開發環境下,可以開啟慢查詢日誌來記錄查詢時間較長的查詢語句,然後對這些語句進行優化。

root@modb:/var/lib/mysql# cat /var/lib/mysql/modb-slow.log
/usr/sbin/mysqld, Version: 8.0.26-0ubuntu0.21.04.3 ((Ubuntu)). started with:
Tcp port: 3306  Unix socket: /var/run/mysqld/mysqld.sock
Time                 Id Command    Argument
root@modb:/var/lib/mysql# 

通過配 long_query_time 的值,可以靈活地掌握不同程度的慢查詢語句。

27、是不是索引建立得越多越好?

合理的索引可以提高查詢的速度,但不是索引越多越好。

在執行插入語句的時候,MySQL 要為新插入的記錄建立索引。所以過多的索引會導致插入操作變慢。原則上是只有查詢用的欄位才建立索引。

使用索引時,需要綜合考慮索引的優點和缺點。

28、如何使用查詢緩衝區?

查詢緩衝區可以提高查詢的速度,但是這種方式只適合查詢語句比較多、更新語句比較少 的情況。

默認情況下查詢緩衝區的大小為 0,也就是不可用。可以修改 queiy_cache_size 以調整查詢緩衝區大小;修改 query_cache_type 以調整查詢緩衝區的類型。

my.cnf 中修改 query_cache_sizequery_cache_type 的值如下所示:

[mysqld]
query_cache_size= 512M 
query_cache_type= 1
query_cache_type=1

表示開啟查詢緩衝區。

只有在查詢語句中包含 SQL_NO_CACHE 關鍵字時,才不會使用查詢緩衝區。可以使用 FLUSH QUERY CACHE 語句來刷新緩衝區,清理查詢緩衝區中的碎片。

這不是秋招快到了嗎?給粉絲準備一份跳槽漲薪的一份大禮,包含近兩年大廠面試題及大廠面經有需要的小夥伴轉發+評論私信【學習】即可免費獲取!

關鍵字: