![](/img/trans.png)
[英]how to extract json keys and values as table with 2 columns mysql 5.7
[英]MySQL 5.7 - JSON Indexing - Generated Columns with non-scalar values
我一直在研究 MySQL 5.7 中的 JSON 支持。 我對出於索引目的生成的列有幾個問題。 https://dev.mysql.com/doc/refman/5.7/en/create-table.html#create-table-secondary-indexes-virtual-columns 。
具體參考這一行:
無法為 JSON 列編制索引。 您可以通過在從 JSON 列中提取標量值的生成列上創建索引來解決此限制。
這對我來說似乎是一個很大的限制。 無論我在哪里,人們都建議使用生成的列。 但該解決方法適用於非常有限的一組用例。 或者,我理解錯了。
讓我解釋一下我的用例。 假設您有一個名為standards
的表。 它具有以下結構:
CREATE TABLE `standards` (
`id` int(11) NOT NULL,
`name` varchar(100) NOT NULL,
`sections` json DEFAULT NULL,
`subjects` json DEFAULT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
sections
列包含一個 JS 對象數組:
[
{
"id": 90491,
"name": "A",
},
{
"id": 90494,
"name": "B",
}
]
subjects
列包含一個嵌套的 JS 對象:
{
"576845": {
"id": 576845,
"name": "Computer Education"
},
"576848": {
"id": 576848,
"name": "English Language"
},
"576854": {
"id": 576854,
"name": "Environmental Science"
},
"576860": {
"id": 576860,
"name": "Mathematics"
}
}
要查找section ID
為90494
的Standard
記錄,查詢將是:
SELECT * from standards WHERE JSON_CONTAINS( sections->>'$[*].id', '90494' );
要查找subject ID
為576854
的Standard
記錄,查詢將是:
SELECT * from standards WHERE JSON_CONTAINS_PATH( subjects, 'one', '$."576854"');
要么
SELECT * from standards WHERE JSON_CONTAINS( subjects->>'$.*.id', '576854' );
現在,以上所有的工作。 問題是查詢執行全表掃描。
考慮上面的查詢 1,我如何生成一個包含所有section IDs
的標量數據的虛擬列?
每個Standard
記錄都有多個sections
,具有多個 ID。 所以,我不能只創建一個整數虛擬列來存儲單個值。 它必須是一個節 ID 數組,我們需要通過它進行搜索。
因此,我生成的列如下所示:
ALTER TABLE standards
ADD section_ids json GENERATED ALWAYS AS (sections->>'$[*].id') VIRTUAL NOT NULL;
生成的列現在將僅存儲部分 ID 數組。 但是我不能在生成的列上添加索引,因為它又是一個 JSON 列。
所以,問題歸結為 - 對於上面顯示的查詢,我如何避免全表掃描?
任何建議,將不勝感激。
我不會說 MySQL 5.7 是不可能的——因為它有笨重的變通方法和限制——但我不會討論如何使用該版本,因為它要困難得多,而且在許多方面都會有限制情況下,如果可以將大量項目添加到數組中,則可以達到。
但是,從現在支持多值索引的 MySQL 8.0.17開始是可能的。
ALTER TABLE standards
ADD INDEX section_ids ( (CAST(sections->'$[*].id' AS UNSIGNED ARRAY)) ),
ADD INDEX subject_ids ( (CAST(subjects->'$.*.id'AS UNSIGNED ARRAY)) );
** 請注意$.*
將采用所有對象屬性並返回每個格式化為數組的查詢值 ( .id
)。
EXPLAIN SELECT * from standards WHERE JSON_CONTAINS( sections->'$[*].id', '90494' );
EXPLAIN SELECT * from standards WHERE JSON_CONTAINS( subjects->'$.*.id', 576854 );
您將看到索引用於這些查詢。
我會在舊版本中通過手動創建一個單獨的索引表並使用觸發器使其保持最新來解決這個問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.