簡介

MySQL 儲存格式中,常用TEXT或BLOB來儲存長字串

兩者之間的差異主要為: TEXT 只能儲存字元資料,BLOB 可以保存二進位資料(圖片..)

通常,根據內文預期的長度來挑選適當的類型

  Type |         Bytes | English words | Multi-byte words

———–+—————+—————+—————– TINYTEXT or TINYBLOB | 255 | ±44 | ±23 TEXT or BLOB | 65,535 | ±11,000 | ±5,900 MEDIUMTEXT or MEDIUMBLOB | 16,777,215 | ±2,800,000 | ±1,500,000 LONGTEXT or LONGBLOB | 4,294,967,295 | ±740,000,000 | ±380,000,000

缺點

兩者在刪除之後,仍會占用空間,長期或大量執行刪除動作時,會產生大量空洞空間,引起性能問題。

定期最佳化表格

透過 OPTIMIZE TABLE 將資料表進行磁碟重組,將空洞空間釋放出來,改善效能。

>OPTIMIZE TABLE 資料表名稱

搜尋

對於 TEXT 與 BLOB 內容進行搜尋,效能較差

因此,有幾個方式可以用來改善查詢表單的性能:

合成索引

合成索引是將TEXT 或 BLOB 的內容,同時存成一個 MD5、SHA1…等散列值。

查詢時,則是將查詢的字串同樣轉成散列值,再來查詢

但是這樣的方式只適合精確匹配的字串,雖然能有效提升效能,卻無法廣泛實用

這裡做一個合成索引範例說明:

我們先建立表單,其中 content 是長內文,hash則是會用來儲存散列值

> CREATE TABLE text_table (id int(10) NOT NULL AUTO_INCREMENT, content text, hash varchar(40), PRIMARY KEY(id));

Query OK, 0 rows affected (0.06 sec)

插入值時,這裡是將 md5(content) 散列值儲存在 hash 欄位

MariaDB [example]> INSERT INTO text_table(`content`,`hash`) VALUES(REPEAT('hi',3), md5(content));
Query OK, 1 row affected (0.00 sec)
MariaDB [example]> INSERT INTO text_table(`content`,`hash`) VALUES(REPEAT('hello',3), md5(content));
Query OK, 1 row affected (0.00 sec)


MariaDB [example]> SELECT * FROM text_table;
+----+-----------------+----------------------------------+
| id | content         | hash                             |
+----+-----------------+----------------------------------+
|  1 | hihi            | e9f5713dec55d727bb35392cec6190ce |
|  2 | hellohellohello | 99fb31087791f6317ad7c6da1433f172 |
+----+-----------------+----------------------------------+
2 rows in set (0.00 sec)

查詢時,則會將搜尋的字串轉乘散列值,再來進行比對

MariaDB [example]> SELECT * FROM text_table WHERE hash=md5('hihi');
+----+---------+----------------------------------+
| id | content | hash                             |
+----+---------+----------------------------------+
|  1 | hihi    | e9f5713dec55d727bb35392cec6190ce |
+----+---------+----------------------------------+
1 row in set (0.00 sec)

首碼索引

MySQL 提供了首碼索引的功能,可以為欄位的前 n 個字元建立索引,來改善查詢的性能

MariaDB [example]> CREATE INDEX IDX_BLOB ON text_table(content(100));
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0

使用 DESC 查看是否已成功使用了索引 這裡執行結果,可以看到已經成功使用前綴 IDX_BLOB


MariaDB [example]> DESC SELECT * FROM text_table WHERE content like 'hi%' \G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: text_table
         type: range
possible_keys: IDX_BLOB
          key: IDX_BLOB
      key_len: 103
          ref: NULL
         rows: 1
        Extra: Using where
1 row in set (0.00 sec)