共計(jì) 8940 個字符,預(yù)計(jì)需要花費(fèi) 23 分鐘才能閱讀完成。
這篇文章主要講解了“MySQL 8.0.23 新特性有哪些”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著丸趣 TV 小編的思路慢慢深入,一起來研究和學(xué)習(xí)“MySQL 8.0.23 新特性有哪些”吧!
在 MySQL 8.0.23 之前,表中所有的列都是可見的(如果您有權(quán)限的話)。現(xiàn)在可以指定一個不可見的列,它將對查詢隱藏。如果顯式引用,它可以被查到。
讓我們看看它是怎樣的:
create table table1 ( id int auto_increment primary key, name varchar(20), age int invisible);
在表結(jié)構(gòu)中我們在 Extra 列可以看到 INVISIBLE 關(guān)鍵字:
desc table1; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int | NO | PRI | NULL | auto_increment | | name | varchar(20) | YES | | NULL | | | age | int | YES | | NULL | INVISIBLE | +-------+-------------+------+-----+---------+----------------+
查看 show create table 語句,注意到有一個不同,當(dāng)我創(chuàng)建表時,我希望看到 INVISIBLE 關(guān)鍵字,但事實(shí)并非如此:
show create table table1\\G ************************* 1. row ************************* Table: table1 Create Table: CREATE TABLE `table1` ( id int NOT NULL AUTO_INCREMENT, name varchar(20) DEFAULT NULL, age int DEFAULT NULL /*!80023 INVISIBLE */, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
但是我確認(rèn)這個語句在創(chuàng)建表時會將 age 列設(shè)置為不可見。所以我們有 2 個不同的語法來創(chuàng)建不可見列。
INFORMATION_SCHEMA 中也可以看到相關(guān)信息:
SELECT TABLE_NAME, COLUMN_NAME, EXTRA FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = test AND TABLE_NAME = table1 +------------+-------------+----------------+ | TABLE_NAME | COLUMN_NAME | EXTRA | +------------+-------------+----------------+ | table1 | id | auto_increment | | table1 | name | | | table1 | age | INVISIBLE | +------------+-------------+----------------+
插入一些數(shù)據(jù),繼續(xù)觀察:
insert into table1 values (0, mysql , 25), (0, kenny , 35), (0, lefred , 44 ERROR: 1136: Column count doesn t match value count at row 1
如預(yù)期,插入語句中如果我們不引用它,會報(bào)錯。引用這些列:
insert into table1 (id, name, age) values (0, mysql , 25), (0, kenny , 35), (0, lefred , 44 Query OK, 3 rows affected (0.1573 sec
查詢表中數(shù)據(jù):
select * from table1; +----+--------+ | id | name | +----+--------+ | 1 | mysql | | 2 | kenny | | 3 | lefred | +----+--------+
再一次,如預(yù)期,我們看到不可見列沒有顯示。
如果我們指定它:
select name, age from table1; +--------+-----+ | name | age | +--------+-----+ | mysql | 25 | | kenny | 35 | | lefred | 44 | +--------+-----+
當(dāng)然我們可以將列從可見轉(zhuǎn)為不可見或者將不可見轉(zhuǎn)為可見:
alter table table1 modify name varchar(20) invisible, modify age integer visible; Query OK, 0 rows affected (0.1934 sec) select * from table1; +----+-----+ | id | age | +----+-----+ | 1 | 25 | | 2 | 35 | | 3 | 44 | +----+-----+
我對這個新功能感到非常高興,在下一篇文章中我們將會看到為什么這對 InnoDB 來說是一個重要的功能。
本文是與 MySQL 不可見列相關(guān)的系列文章的第二部分。
這篇文章介紹了為什么不可見列對 InnoDB 存儲引擎很重要。
首先,讓我簡單解釋一下 InnoDB 是如何處理主鍵的,以及為什么一個好的主鍵很重要。最后,為什么主鍵也很重要。
InnoDB 如何存儲數(shù)據(jù)?
InnoDB 在表空間存儲數(shù)據(jù)。這些記錄存儲并用聚簇索引排序(主鍵):它們被稱為索引組織表。
所有的二級索引也將主鍵作為索引中的最右邊的列(即使沒有公開)。這意味著當(dāng)使用二級索引檢索一條記錄時,將使用兩個索引:二級索引指向用于最終檢索該記錄的主鍵。
主鍵會影響隨機(jī) I / O 和順序 I / O 之間的比率以及二級索引的大小。
隨機(jī)主鍵還是順序主鍵?
如上所述,數(shù)據(jù)存儲在聚簇索引中的表空間中。這意味著如果您不使用順序索引,當(dāng)執(zhí)行插入時,InnoDB 不得不重平衡表空間的所有頁。
如果我們用 InnoDB Ruby 來說明這個過程,下面的圖片顯示了當(dāng)使用隨機(jī)字符串作為主鍵插入記錄時表空間是如何更新的:
每次有一個插入,幾乎所有的頁都會被觸及。
當(dāng)使用自增整型作為主鍵時,同樣的插入:
自增主鍵的情況下,只有第一個頁和最后一個頁才會被觸及。
讓我們用一個高層次的例子來解釋這一點(diǎn):
假設(shè)一個 InnoDB 頁可以存儲 4 條記錄(免責(zé)聲明:這只是一個虛構(gòu)的例子),我們使用隨機(jī)主鍵插入了一些記錄:
插入新記錄,主鍵為 AA!
修改所有頁以 重新平衡 聚簇索引,在連續(xù)主鍵的情況下,只有最后一個頁面會被修改。想象一下成千上萬的插入發(fā)生時所要做的額外工作。
這意味著選擇好的主鍵是重要的。需要注意兩點(diǎn):
主鍵必須連續(xù)。
主鍵必須短。
UUID 怎么樣?
我通常建議使用自增整型 (或 bigint) 作為主鍵,但是不要忘記監(jiān)控它們!
但我也明白越來越多的開發(fā)人員喜歡使用 uuid。
如果您打算使用 UUID,您應(yīng)該閱讀 MySQL8.0 中 UUID 的支持,這篇文章推薦您用 binary(16) 存儲 UUID。
如:
CREATE TABLE t (id binary(16) PRIMARY KEY); INSERT INTO t VALUES(UUID_TO_BIN(UUID()));
然而,我并不完全同意這個觀點(diǎn),為什么?
因?yàn)槭褂?uuid_to_bin() 可能會改變 MySQL 的 UUID 實(shí)現(xiàn)的順序行為(有關(guān)更多信息,請參閱額外部分)。
但是如果您需要 UUID,你需要在大索引上花費(fèi)一定代價(jià),索引不要浪費(fèi)存儲和內(nèi)存在不需要的二級索引上:
select * from sys.schema_unused_indexes where object_schema not in (performance_schema , mysql
沒有任何主鍵?
對 InnoDB 表來說,當(dāng)沒有定義主鍵,會使用第一個唯一非空列。如果沒有可用的列,InnoDB 會創(chuàng)建一個隱藏主鍵(6 位)。
這類主鍵的問題在于您無法控制它,更糟糕的是,這個值對所有沒有主鍵的表是全局的,如果您同時對這些表執(zhí)行多次寫操作,可能會產(chǎn)生爭用問題(dict_sys- mutex)。
不可見列的用處
有了新的不可見列,如果應(yīng)用不允許添加新列,我們現(xiàn)在就可以向沒有主鍵的表添加合適的主鍵。
首先先找到這些表:
SELECT tables.table_schema , tables.table_name , tables.engine FROM information_schema.tables LEFT JOIN ( SELECT table_schema , table_name FROM information_schema.statistics GROUP BY table_schema, table_name, index_name HAVING SUM( case when non_unique = 0 and nullable != YES then 1 else 0 end ) = count(*) ) puks ON tables.table_schema = puks.table_schema AND tables.table_name = puks.table_name WHERE puks.table_name IS null AND tables.table_type = BASE TABLE AND Engine= InnoDB +--------------+--------------+--------+ | TABLE_SCHEMA | TABLE_NAME | ENGINE | +--------------+--------------+--------+ | test | table2 | InnoDB | +--------------+--------------+--------+
您也可以使用 MySQL Shell 中的校驗(yàn)插件:https://github.com/lefred/mysqlshell-plugins/wiki/check#getinnodbtableswithnopk
讓我們查看表定義:
show create table table2\\G *************** 1. row *************** Table: table2 Create Table: CREATE TABLE table2 ( name varchar(20) DEFAULT NULL, age int DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
其中的數(shù)據(jù):
select * from table2; +--------+-----+ | name | age | +--------+-----+ | mysql | 25 | | kenny | 35 | | lefred | 44 | +--------+-----+
現(xiàn)在添加指定不可見主鍵:
alter table table2 add column id int unsigned auto_increment primary key invisible first;
插入一條新記錄:
insert into table2 (name, age) values (PHP , 25); select * from table2; +--------+-----+ | name | age | +--------+-----+ | mysql | 25 | | kenny | 35 | | lefred | 44 | | PHP | 25 | +--------+-----+
如果我們想要查看主鍵:
select id, table2.* from table2; +----+--------+-----+ | id | name | age | +----+--------+-----+ | 1 | mysql | 25 | | 2 | kenny | 35 | | 3 | lefred | 44 | | 4 | PHP | 25 | +----+--------+-----+
總結(jié)
現(xiàn)在您知道 InnoDB 中為什么主鍵很重要,為什么一個好的主鍵更重要。
從 MySQL8.0.23 開始,您可以用不可見列解決沒有主鍵的表。
額外
僅為娛樂,并說明我對使用 UUID_TO_BIN(UUID()) 作為主鍵的看法,讓我們重新使用 UUID 作為不可見列重復(fù)這個例子。
alter table table2 add column id binary(16) invisible first; alter table table2 modify column id binary(16) default (UUID_TO_BIN(UUID())) invisible; update table2 set id=uuid_to_bin(uuid()); alter table table2 add primary key(id);
到目前還沒什么特別的,只是創(chuàng)建不可見主鍵需要一些技巧。
查詢:
select * from table2; +--------+-----+ | name | age | +--------+-----+ | mysql | 25 | | kenny | 35 | | lefred | 44 | +--------+-----+
現(xiàn)在,我們再向這個表插入一條新數(shù)據(jù):
insert into table2 (name, age) values (PHP , 25); select * from table2; +--------+-----+ | name | age | +--------+-----+ | PHP | 25 | | mysql | 25 | | kenny | 35 | | lefred | 44 | +--------+-----+
Mmmm… 為什么 PHP 現(xiàn)在是第一行?
因?yàn)?uuid() 并不連續(xù) …
select bin_to_uuid(id), table2.* from table2; +--------------------------------------+--------+-----+ | bin_to_uuid(id) | name | age | +--------------------------------------+--------+-----+ | 05aedcbd-5b36-11eb-94c0-c8e0eb374015 | PHP | 25 | | af2002e8-5b35-11eb-94c0-c8e0eb374015 | mysql | 25 | | af20117a-5b35-11eb-94c0-c8e0eb374015 | kenny | 35 | | af201296-5b35-11eb-94c0-c8e0eb374015 | lefred | 44 | +--------------------------------------+--------+-----+
我們還有別的選擇嗎?
是的,如果我們參考官檔,我們可以使用 uuid_to_bin() 函數(shù)。
alter table table2 add column id binary(16) invisible first; alter table table2 modify column id binary(16) default (UUID_TO_BIN(UUID(),1)) invisible; update table2 set id=uuid_to_bin(uuid(),1);
現(xiàn)在我們每次插入一條新記錄,插入如期望一樣是順序的:
select bin_to_uuid(id,1), table2.* from table2; +--------------------------------------+--------+-----+ | bin_to_uuid(id,1) | name | age | +--------------------------------------+--------+-----+ | 5b3711eb-023c-e634-94c0-c8e0eb374015 | mysql | 25 | | 5b3711eb-0439-e634-94c0-c8e0eb374015 | kenny | 35 | | 5b3711eb-0471-e634-94c0-c8e0eb374015 | lefred | 44 | | f9f075f4-5b37-11eb-94c0-c8e0eb374015 | PHP | 25 | | 60ccffda-5b38-11eb-94c0-c8e0eb374015 | PHP8 | 1 | | 9385cc6a-5b38-11eb-94c0-c8e0eb374015 | Python | 20 | +--------------------------------------+--------+-----+
我們之前看了從 MySQL8.0.23 后,新的不可見列的功能。如果主鍵沒有定義,我們?nèi)绾问褂盟鼮?InnoDB 表添加主鍵。
如之前所述,好的主鍵對 InnoDB 很重要 (存儲,IOPS,二級索引,內(nèi)存等) 但是 MySQL 中主鍵還有一個重要的作用:復(fù)制!
異步復(fù)制
當(dāng)使用 傳統(tǒng)復(fù)制 時,如果您修改了一行記錄(更新和刪除),那么要在副本上修改的記錄將使用索引來標(biāo)識,當(dāng)然如果有主鍵的話,還會使用主鍵。InnoDB 自動生成的隱藏全局 6 字節(jié)主鍵永遠(yuǎn)不會被使用,因?yàn)樗侨值模圆荒鼙WC源和副本之間是相同的。你根本不應(yīng)該考慮它。
如果算法不能找到合適的索引,或者只能找到一個非唯一索引或者包含 null 值,則需要使用哈希表來識別表記錄。該算法創(chuàng)建一個哈希表,其中包含更新或者刪除操作的記錄,并用鍵作為該行之前完整的映像。然后,該算法遍歷目標(biāo)表中的所有記錄,如果找到了所選索引,則使用該索引,否則執(zhí)行全表掃描(參見官檔)。
因此,如果應(yīng)用程序不支持使用額外的鍵作為主鍵,則使用隱藏列作為主鍵是加快復(fù)制的一個方法。
mysql create table t1 (name varchar(20), age int); mysql insert into t1 values (mysql ,25),(kenny , 35),(lefred , 44);
現(xiàn)在添加一個自增列作為主鍵:
mysql alter table t1 add id int auto_increment primary key first;
然后按照應(yīng)用程序中指定的 INSERT 語句添加一條記錄:
mysql insert into t1 values (python ,20); ERROR: 1136: Column count doesn t match value count at row 1
最好的方法是修改應(yīng)用的 INSERT 語句,但是可能嗎?
多少應(yīng)用程序仍然是使用 SELECT *,并且引用列時如 col[2]?
如果是這樣,您有兩種方法:
分析所有的查詢,使用重寫查詢插件
使用不可見列
在這種情況下,選擇是容易的(至少對像我這樣的懶人說)。
mysql alter table t1 modify id int auto_increment invisible; mysql insert into t1 values (python ,20); Query OK, 1 row affected (0.0887 sec)
很簡單,不是嗎?
組復(fù)制
MySQL InnoDB Cluster 使用另一種復(fù)制:Group Replication。
使用組復(fù)制的要求之一是要有一個主鍵(這就是為什么可以使用 sql_require_primary_key)。
我們使用上例中重構(gòu)表,不加主鍵,檢查該實(shí)例能否作為 InnoDB Cluster:
https://lefred.be/wp-content/uploads/2021/01/Selection_9991017-1024×561.png
提示很清楚,該表上的修改不會復(fù)制到其他節(jié)點(diǎn)。
添加不可見主鍵,重新檢查:
這意味著,如果應(yīng)用程序使用的表沒有主鍵,不允許遷移到 MySQL InnoDB Cluster 等高可用架構(gòu)中,現(xiàn)在多虧了不可見列,這可以做到了。
感謝各位的閱讀,以上就是“MySQL 8.0.23 新特性有哪些”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對 MySQL 8.0.23 新特性有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是丸趣 TV,丸趣 TV 小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!