InnoDB
支援虛擬產生欄上的次要索引。不支援其他索引類型。在虛擬欄上定義的次要索引有時稱為「虛擬索引」。
可以在一個或多個虛擬欄上,或在虛擬欄和一般欄或儲存的產生欄的組合上建立次要索引。包含虛擬欄的次要索引可以定義為 UNIQUE
。
當在虛擬產生欄上建立次要索引時,產生的欄值會具體化在索引的記錄中。如果索引是涵蓋索引(包含查詢檢索的所有欄的索引),則產生的欄值會從索引結構中具體化的值中檢索,而不是「即時」計算。
在虛擬欄位上使用次要索引時,由於在 INSERT
和 UPDATE
操作期間,於次要索引記錄中具體化虛擬欄位值時會執行計算,因此需要考量額外的寫入成本。即使有額外的寫入成本,虛擬欄位上的次要索引可能仍然優於產生的儲存欄位,因為後者會在叢集索引中具體化,導致更大的資料表,需要更多的磁碟空間和記憶體。如果未在虛擬欄位上定義次要索引,則讀取時會有額外的成本,因為每次檢查欄位的資料列時都必須計算虛擬欄位值。
索引虛擬欄位的值會進行 MVCC 記錄,以避免在回滾或清除操作期間不必要地重新計算產生的欄位值。記錄值的資料長度受限於 COMPACT
和 REDUNDANT
列格式的索引鍵限制 767 位元組,以及 DYNAMIC
和 COMPRESSED
列格式的 3072 位元組。
在虛擬欄位上新增或刪除次要索引是一種就地操作。
如其他地方所述,JSON
欄位無法直接建立索引。若要建立間接參照此類欄位的索引,您可以定義一個產生的欄位,其會提取應該被索引的資訊,然後在產生的欄位上建立索引,如下例所示
mysql> CREATE TABLE jemp (
-> c JSON,
-> g INT GENERATED ALWAYS AS (c->"$.id"),
-> INDEX i (g)
-> );
Query OK, 0 rows affected (0.28 sec)
mysql> INSERT INTO jemp (c) VALUES
> ('{"id": "1", "name": "Fred"}'), ('{"id": "2", "name": "Wilma"}'),
> ('{"id": "3", "name": "Barney"}'), ('{"id": "4", "name": "Betty"}');
Query OK, 4 rows affected (0.04 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT c->>"$.name" AS name
> FROM jemp WHERE g > 2;
+--------+
| name |
+--------+
| Barney |
| Betty |
+--------+
2 rows in set (0.00 sec)
mysql> EXPLAIN SELECT c->>"$.name" AS name
> FROM jemp WHERE g > 2\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: jemp
partitions: NULL
type: range
possible_keys: i
key: i
key_len: 5
ref: NULL
rows: 2
filtered: 100.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
Level: Note
Code: 1003
Message: /* select#1 */ select json_unquote(json_extract(`test`.`jemp`.`c`,'$.name'))
AS `name` from `test`.`jemp` where (`test`.`jemp`.`g` > 2)
1 row in set (0.00 sec)
(我們已將此範例中最後一個陳述式的輸出換行,以符合檢視區域。)
當您在包含一個或多個使用 ->
或 ->>
運算子的表達式的 SELECT
或其他 SQL 陳述式上使用 EXPLAIN
時,這些表達式會轉換為使用 JSON_EXTRACT()
以及(如果需要)JSON_UNQUOTE()
的對等表達式,如下列 SHOW WARNINGS
陳述式緊接著此 EXPLAIN
陳述式的輸出所示
mysql> EXPLAIN SELECT c->>"$.name"
> FROM jemp WHERE g > 2 ORDER BY c->"$.name"\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: jemp
partitions: NULL
type: range
possible_keys: i
key: i
key_len: 5
ref: NULL
rows: 2
filtered: 100.00
Extra: Using where; Using filesort
1 row in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
Level: Note
Code: 1003
Message: /* select#1 */ select json_unquote(json_extract(`test`.`jemp`.`c`,'$.name')) AS
`c->>"$.name"` from `test`.`jemp` where (`test`.`jemp`.`g` > 2) order by
json_extract(`test`.`jemp`.`c`,'$.name')
1 row in set (0.00 sec)
如需其他資訊和範例,請參閱 ->
和 ->>
運算子,以及 JSON_EXTRACT()
和 JSON_UNQUOTE()
函式的說明。
此技術也可用於提供間接參照無法直接索引的其他類型欄位的索引,例如 GEOMETRY
欄位。
也可以使用 JSON_VALUE()
函式在 JSON
欄位上建立索引,其中該函式具有可用於最佳化採用該表達式的查詢的表達式。請參閱該函式的說明以取得更多資訊和範例。
NDB Cluster 中的 JSON 欄位和間接索引
在符合以下條件的情況下,也可以在 MySQL NDB Cluster 中使用 JSON 欄位的間接索引
用於建立此處顯示的資料表 jempn
的 CREATE TABLE
陳述式是先前顯示的 jemp
資料表的版本,並進行了修改使其與 NDB
相容
CREATE TABLE jempn (
a BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
c JSON DEFAULT NULL,
g INT GENERATED ALWAYS AS (c->"$.id") STORED,
INDEX i (g)
) ENGINE=NDB;
我們可以使用以下 INSERT
陳述式來填入此資料表
INSERT INTO jempn (c) VALUES
('{"id": "1", "name": "Fred"}'),
('{"id": "2", "name": "Wilma"}'),
('{"id": "3", "name": "Barney"}'),
('{"id": "4", "name": "Betty"}');
現在,NDB
可以使用索引 i
,如下所示
mysql> EXPLAIN SELECT c->>"$.name" AS name
-> FROM jempn WHERE g > 2\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: jempn
partitions: p0,p1,p2,p3
type: range
possible_keys: i
key: i
key_len: 5
ref: NULL
rows: 3
filtered: 100.00
Extra: Using pushed condition (`test`.`jempn`.`g` > 2)
1 row in set, 1 warning (0.01 sec)
mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
Level: Note
Code: 1003
Message: /* select#1 */ select
json_unquote(json_extract(`test`.`jempn`.`c`,'$.name')) AS `name` from
`test`.`jempn` where (`test`.`jempn`.`g` > 2)
1 row in set (0.00 sec)
您應該記住,儲存的產生欄位,以及該欄位上的任何索引,都會使用 DataMemory
。