當(dāng)前位置:首頁 > IT技術(shù) > 數(shù)據(jù)庫 > 正文

MySQL 全文索引 (FullText)
2021-09-10 19:12:50

MySQL 全文索引

一、簡介

基本概念

全文索引是為了解決需要基于相似度的查詢,而不是精確數(shù)值比較。

雖然使用 like + % 也可以實現(xiàn)模糊匹配,但是對于大量的文本數(shù)據(jù)檢索,是不可想象的。全文索引在大量的數(shù)據(jù)面前,能比 like 快 N 倍,速度不是一個數(shù)量級。

版本支持

  1. MySQL 5.6 以前的版本,只有 MyISAM 存儲引擎支持全文索引
  2. MySQL 5.6 及以后的版本,MyISAMInnoDB 存儲引擎均支持全文索引
  3. MySQL 5.7.6 中,提供了支持中文、日文和韓文(CJK)的內(nèi)置全文 ngram 解析器,以及用于日文的可安裝 MeCab 全文解析器插件
  4. 全文索引只能用于InnoDBMyISAM表,只能為CHARVARCHAR、TEXT列創(chuàng)建
  5. 對于大型數(shù)據(jù)集,<span style="" quot="quot" dashed="""dashed""" yellow="""yellow""">將數(shù)據(jù)加載到?jīng)]有全文索引的表中然后創(chuàng)建索引要比將數(shù)據(jù)加載到具有現(xiàn)有全文索引的表中快得多
  6. RDS MySQL 5.6 雖然也支持中文全文檢索,但存在BUG

限制與缺點

  • 導(dǎo)致磁盤資源的大量占用。全文索引本身就是一個利用磁盤空間換取性能的方法。全文索引大的原因是,按照某種語言來進(jìn)行分詞
  • 全文索引創(chuàng)建速度慢,而且對有全文索引的各種數(shù)據(jù)修改操作也慢
  • 使用全文索引并不是對應(yīng)用透明的。如果要想利用全文索引,必須修改查詢語句。原有的查詢語句是不可能利用全文索引的,需要改成全文索引規(guī)定的語法
  • 不區(qū)分大小寫
  • 分區(qū)表不支持全文搜索
  • 由多列組合而成的全文檢索的索引必須使用相同的字符集與排序規(guī)則
  • 全文索引可能存在精度問題,即全文索引找到的數(shù)據(jù),可能和like到的不一致
  • MATCH()函數(shù)中的列必須與FULLTEXT索引中定義的列完全一致,除非是在MyISAM表中使用IN BOOLEAN MODE模式的全文搜索(可在沒有建立索引的列執(zhí)行搜索,但速度很慢)
  • 單列分別建立全文索引時,多列模糊查詢時不生效
  • 不同表的全文索引不能放在一起查詢,可以兩個語句中加上OR

二、操作全文索引

2.1 配置最小搜索長度

我們可以通過 SQL 命令查看當(dāng)前配置的最小搜索長度(分詞長度):

SHOW VARIABLES LIKE 'ft%';
Variable_name Value
ft_boolean_syntax + -><()~*:""&|
ft_max_word_len 84
ft_min_word_len 1
ft_query_expansion_limit 20
ft_stopword_file (built-in)

全文索引的相關(guān)參數(shù)都無法進(jìn)行動態(tài)修改,必須通過修改 MySQL 的配置文件來完成。修改最小搜索長度的值為 1,首先打開 MySQL 的配置文件 /etc/my.cnf,在 [mysqld] 的下面追加以下內(nèi)容:

[mysqld]
innodb_ft_min_token_size = 1
# 最短的索引字符串,默認(rèn)值為4
ft_min_word_len = 1

配置完后重啟 MySQL 服務(wù)器,并修復(fù)或重建全文索引方可生效。
可使用下面的命令修復(fù):

repair table test quick;

2.2 創(chuàng)建索引

  • 建表時創(chuàng)建全文索引
CREATE TABLE fulltext_test (
  id int(11) NOT NULL AUTO_INCREMENT,
	content TEXT NOT NULL,
	tag VARCHAR(255),
	PRIMARY KEY (id),
	FULLTEXT KEY content_tag_fulltext(content, tag) WITH PARSER ngram
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4;
  • 在已存在的表上創(chuàng)建全文索引
CREATE FULLTEXT INDEX content_fulltext ON fulltext_test(content) with parser ngram;
  • 通過 SQL 語句 ALTER TABLE 創(chuàng)建全文索引
ALTER TABLE fulltext_test ADD FULLTEXT INDEX content_fulltext(content) with parser ngram;

2.3 刪除索引

  • 使用 DROP INDEX 刪除全文索引
DROP INDEX content_fulltext ON fulltext_test;
  • 通過 SQL 語句 ALTER TABLE 刪除全文索引
ALTER TABLE fulltext_test DROP INDEX content_fulltext;

三、檢索數(shù)據(jù)

3.1 自然語言的全文檢索

默認(rèn)情況下,或者使用 in natural language mode 修飾符時,match() 函數(shù)對文本集合執(zhí)行自然語言搜索。

SELECT * FROM 表名 WHERE Match(列名1,列名2) Against (檢索內(nèi)容1 檢索內(nèi)容2);

檢索內(nèi)容不需要用逗號隔開!

自然語言搜索引擎將計算每一個文檔對象和查詢的相關(guān)度。這里,相關(guān)度是基于匹配的關(guān)鍵詞的個數(shù),以及關(guān)鍵詞在文檔中出現(xiàn)的次數(shù)。在整個索引中出現(xiàn)次數(shù)越少的詞語,匹配時的相關(guān)度就越高。相反,非常常見的單詞將不會被搜索,如果一個詞語的在超過 50% 的記錄中都出現(xiàn)了,那么自然語言的搜索將不會搜索這類詞語。

3.2 布爾全文檢索

在布爾搜索中,我們可以在查詢中自定義某個被搜索的詞語的相關(guān)性,當(dāng)編寫一個布爾搜索查詢時,可以通過一些前綴修飾符來定制搜索。

  • 空(也就是默認(rèn)狀況),表示可選的,包含該詞的順序較高
  • + 表示必須包含
  • - 表示必須排除
  • “>” 表示出現(xiàn)該單詞時增加相關(guān)性,查詢的結(jié)果靠前
  • “<” 表示出現(xiàn)該單詞時降低相關(guān)性,查詢的結(jié)果靠后
  • * 表示通配符,只能接在詞后面
  • ~ 允許出現(xiàn)該單詞,但是出現(xiàn)時相關(guān)性為負(fù),表示擁有該字會下降相關(guān)性,但不像「-」將之排除,只是排在較后面
  • "" 雙引號表示短語,表示要徹底相符,不可拆字效果,類同于 like '%keyword%'
  • () 經(jīng)過括號來使用字條件:
+aaa +(>bbb <ccc) aaa="aaa" sql="sql" select="select" from="from" test="test" where="where" match="match" against="against" in="in" boolean="boolean" mode="mode" select="select" from="from" tommy="tommy" where="where" match="match" against="against" in="in" boolean="boolean" mode="mode" select="select" from="from" tommy="tommy" where="where" match="match" against="against">李秀琴 <練習(xí)冊 <不是人>是個鬼' in boolean mode);

四、測試結(jié)果

測試環(huán)境:本機(jī)4核16G Windows10,MySQL 8.0
測試數(shù)據(jù)量salebilldetail1276萬行,salebill269 萬行, customer30 萬行, goods75 萬行。

爭對測試用的SQL語句,增加了以下全文索引:

CREATE FULLTEXT INDEX billno_fulltext ON salebill(billno) WITH PARSER ngram;
CREATE FULLTEXT INDEX remarks_fulltext ON salebill(remarks) WITH PARSER ngram;
CREATE FULLTEXT INDEX remarks_fulltext ON salebilldetail(remarks) WITH PARSER ngram;
CREATE FULLTEXT INDEX goodsremarks_fulltext ON salebilldetail(goodsremarks) WITH PARSER ngram;
CREATE FULLTEXT INDEX remarks_goodsremarks_fulltext ON salebilldetail(remarks, goodsremarks) WITH PARSER ngram;
CREATE FULLTEXT INDEX custname_fulltext ON customer(custname) WITH PARSER ngram;
CREATE FULLTEXT INDEX goodsname_fulltext ON goods(goodsname) WITH PARSER ngram;
CREATE FULLTEXT INDEX goodscode_fulltext ON goods(goodscode) WITH PARSER ngram;

測試結(jié)果,總的來說很魔幻。
為什么魔幻,看下面幾個語句:

test_1

-- 測試1,原始 like 查詢方式,用時 0.765s
select 1 from salebilldetail d where d.tid=260434 and ((d.remarks like concat('%','葡萄','%')) or (d.goodsremarks like concat('%','葡萄','%')));

test_2

-- 測試2,使用全文索引 remarks_fulltext、goodsremarks_fulltext, 用時 0.834s
select 1 from salebilldetail d where d.tid=260434 and ((match(d.remarks) Against(concat('"','葡萄','"') in boolean mode)) or (match(d.goodsremarks) Against(concat('"','葡萄','"')  in boolean mode)));

test_3

-- 測試3,使用全文索引 remarks_goodsremarks_fulltext, 用時 0.242s
select 1 from salebilldetail d where d.tid=260434 and ((match(d.remarks,d.goodsremarks) Against(concat('"','葡萄','"') in boolean mode)));

test_4

-- 測試4,原始 like 查詢方式,不過濾 tid ,用時 22.654s
select t from salebilldetail d where ((d.remarks like concat('%','葡萄','%')) or (d.goodsremarks like concat('%','葡萄','%')));

test_5

-- 測試5,使用全文索引 remarks_fulltext、goodsremarks_fulltext,  不過濾 tid ,用時 24.855s
select 1 from salebilldetail d where ((match(d.remarks) Against(concat('"','葡萄','"') in boolean mode)) or (match(d.goodsremarks) Against(concat('"','葡萄','"')  in boolean mode)));

test_6

-- 測試6,使用全文索引 remarks_goodsremarks_fulltext, 不過濾 tid ,用時 0.213s
select 1 from salebilldetail d where ((match(d.remarks,d.goodsremarks) Against(concat('"','葡萄','"') in boolean mode)));

test_7

-- 測試7,使用全文索引 remarks_goodsremarks_fulltext, 用時 0.22s
select count(1) from salebilldetail d where d.tid=260434 and  ((match(d.remarks,d.goodsremarks) Against(concat('"','葡萄','"') in boolean mode)));

test_8

-- 測試8,使用全文索引 remarks_goodsremarks_fulltext, 不過濾 tid ,用時 0.007s
select count(1) from salebilldetail d where ((match(d.remarks,d.goodsremarks) Against(concat('"','葡萄','"') in boolean mode)));

從上面的測試語句可以看出,數(shù)據(jù)量越多,查詢越簡單,全文索引的效果越好。

再來看看我們的業(yè)務(wù)測試SQL:

test_9

-- 測試9
select 
    i.billid
    ,if(0,0,i.qty) as qty  
    ,if(0,0,i.goodstotal) as total          
    ,if(0,0,i.chktotal) as selfchktotal   
    ,if(0,0,i.distotal) as distotal 
    ,if(0,0,i.otherpay) as feetotal  
    ,if(0,0,ifnull(d.costtotal,0)) as costtotal  
    ,if(0,0,ifnull(d.maoli,0)) as maoli         
    ,i.billno
    ,from_unixtime(i.billdate,'%Y-%m-%d') as billdate /*單據(jù)日期*/
    ,from_unixtime(i.createdate,'%Y-%m-%d %H:%i:%s') as createdate /*制單日期*/
    ,if(i.sdate=0,'',from_unixtime(i.sdate,'%Y-%m-%d  %H:%i:%s')) as sdate /*過賬日期*/
    ,from_unixtime(i.udate,'%Y-%m-%d %H:%i:%s') as udate /*最后修改時間*/
    ,i.custid ,c.custname
    ,i.storeid ,k.storename
    ,i.empid ,e.empname
    ,i.userid ,u.username
    ,i.remarks                               /*單據(jù)備注*/
    ,i.effect,i.settle,i.redold,i.rednew     /*單據(jù)狀態(tài)*/
    ,i.printtimes /* 打印次數(shù) */
    ,(case  when i.rednew=1 then 1  when i.redold=1 then 2  when i.settle=1 then 3  when i.effect=1 then 4  else 9 end) as state /*單據(jù)狀態(tài)*/
    ,(case  when i.rednew=1 then '紅沖單'  when i.redold=1 then '已紅沖'  when i.settle=1 then '已結(jié)算'  when i.effect=1 then '已過賬'  else '草稿' end) as statetext
    ,'' as susername /* 操作人 */
    ,'' as accname /* 科目 */
from salebill i
left join coursecentersale d on d.tid=i.tid and d.billid=i.billid
left join customer c on c.tid=i.tid and c.custid=i.custid
left join store k on k.tid=i.tid and k.storeid=i.storeid
left join employee e on e.tid=i.tid and e.empid=i.empid
left join user u on u.tid=i.tid and u.userid=i.userid
where i.tid=260434 and (i.billtype = 5 or i.effect = 1)
    and ('_billdate_f_'!='')
    and ('_billdate_t_'!='')
    and ('_sdate_f_'!='')
    and ('_sdate_t_'!='')
    and ('_udate_f_'!='')
    and ('_udate_t_'!='')
    and ('_cdate_f_'!='')
    and ('_cdate_t_'!='')
    and ('_billid_'!='')      /*單據(jù)id*/
    and ('_custid_'!='')      /*客戶ID*/
    and ('_storeid_'!='')     /*店倉ID*/
    and ('_empid_'!='')       /*業(yè)務(wù)員ID*/
    and ('_custstop_'!='')       /*客戶是否停用*/
    and (
        (i.billno like concat('%','葡萄','%'))
        or (i.remarks like concat('%','葡萄','%'))
        or exists(select 1 from salebilldetail d where d.tid=260434 and d.billid=i.billid and ((d.remarks like concat('%','葡萄','%')) or (d.goodsremarks like concat('%','葡萄','%'))))
        or exists(select 1 from customer c where c.tid=260434 and c.custid=i.custid and (c.custname like concat('%','葡萄','%')))
        or exists(select 1 from goods g join salebilldetail d on d.tid=g.tid and d.goodsid=g.goodsid where d.tid=260434 and d.billid=i.billid and ((g.goodsname like concat('%','葡萄','%')) or (g.goodscode like concat('%','葡萄','%'))))
    )
    and i.rednew=0 /*單據(jù)列表不含紅沖單*/ 
    and i.billid not in (select billid from coursecenter_del t where t.tid=260434)
    and ((i.settle=1 and i.effect=1 and i.redold=0 and i.rednew=0)) /*已結(jié)算*/
order by udate desc,billno desc
limit 0,100;

執(zhí)行時間約 1.6 秒,使用的是 like 方式。

改成使用全文索引方式:

test_10

-- 測試10
select 
    i.billid
    ,if(0,0,i.qty) as qty         
    ,if(0,0,i.goodstotal) as total   
    ,if(0,0,i.chktotal) as selfchktotal  
    ,if(0,0,i.distotal) as distotal 
    ,if(0,0,i.otherpay) as feetotal  
    ,if(0,0,ifnull(d.costtotal,0)) as costtotal 
    ,if(0,0,ifnull(d.maoli,0)) as maoli  
    ,i.billno
    ,from_unixtime(i.billdate,'%Y-%m-%d') as billdate /*單據(jù)日期*/
    ,from_unixtime(i.createdate,'%Y-%m-%d %H:%i:%s') as createdate /*制單日期*/
    ,if(i.sdate=0,'',from_unixtime(i.sdate,'%Y-%m-%d  %H:%i:%s')) as sdate /*過賬日期*/
    ,from_unixtime(i.udate,'%Y-%m-%d %H:%i:%s') as udate /*最后修改時間*/
    ,i.custid ,c.custname
    ,i.storeid ,k.storename
    ,i.empid ,e.empname
    ,i.userid ,u.username
    ,i.remarks                               /*單據(jù)備注*/
    ,i.effect,i.settle,i.redold,i.rednew     /*單據(jù)狀態(tài)*/
    ,i.printtimes /* 打印次數(shù) */
    ,(case  when i.rednew=1 then 1  when i.redold=1 then 2  when i.settle=1 then 3  when i.effect=1 then 4  else 9 end) as state /*單據(jù)狀態(tài)*/
    ,(case  when i.rednew=1 then '紅沖單'  when i.redold=1 then '已紅沖'  when i.settle=1 then '已結(jié)算'  when i.effect=1 then '已過賬'  else '草稿' end) as statetext
    ,'' as susername /* 操作人 */
    ,'' as accname /* 科目 */
from salebill i
left join coursecentersale d on d.tid=i.tid and d.billid=i.billid
left join customer c on c.tid=i.tid and c.custid=i.custid
left join store k on k.tid=i.tid and k.storeid=i.storeid
left join employee e on e.tid=i.tid and e.empid=i.empid
left join user u on u.tid=i.tid and u.userid=i.userid
where i.tid=260434 and (i.billtype = 5 or i.effect = 1)
    and ('_billdate_f_'!='')
    and ('_billdate_t_'!='')
    and ('_sdate_f_'!='')
    and ('_sdate_t_'!='')
    and ('_udate_f_'!='')
    and ('_udate_t_'!='')
    and ('_cdate_f_'!='')
    and ('_cdate_t_'!='')
    and ('_billid_'!='')      /*單據(jù)id*/
    and ('_custid_'!='')      /*客戶ID*/
    and ('_storeid_'!='')     /*店倉ID*/
    and ('_empid_'!='')       /*業(yè)務(wù)員ID*/
    and ('_custstop_'!='')       /*客戶是否停用*/
    and (
        (match(i.billno) against(concat('"','葡萄','"') in boolean mode))
        or (match(i.remarks) against(concat('"','葡萄','"') in boolean mode))
        or exists(select 1 from salebilldetail d where d.tid=260434 and d.billid=i.billid and ((match(d.remarks) Against(concat('"','葡萄','"') in boolean mode)) or (match(d.goodsremarks) Against(concat('"','葡萄','"')  in boolean mode))))
        or exists(select 1 from customer c where c.tid=260434 and c.custid=i.custid and (match(c.custname) Against(concat('"','葡萄','"') in boolean mode)))
        or exists(select 1 from goods g join salebilldetail d on d.tid=g.tid and d.goodsid=g.goodsid where d.tid=260434 and d.billid=i.billid 
     and ((match(g.goodsname) Against(concat('"','葡萄','"') in boolean mode))
     or (match(g.goodscode) Against(concat('"','葡萄','"') in boolean mode))))
    )
    and i.rednew=0 /*單據(jù)列表不含紅沖單*/ 
    and i.billid not in (select billid from coursecenter_del t where t.tid=260434)
    and ((i.settle=1 and i.effect=1 and i.redold=0 and i.rednew=0)) /*已結(jié)算*/
order by udate desc,billno desc
limit 0,100;

執(zhí)行時間約 1.6 秒,與使用的是 like 方式差不多。

最魔幻的地方來了,如果將上面的SQL語句中(salebilldetail表使用全文索引 remarks_fulltext、goodsremarks_fulltext的地方)

exists(select 1 from salebilldetail d where d.tid=260434 and d.billid=i.billid and ((match(d.remarks) Against(concat('"','葡萄','"') in boolean mode)) or (match(d.goodsremarks) Against(concat('"','葡萄','"')  in boolean mode))))

test_11

改成使用全文索引 remarks_goodsremarks_fulltext

-- 測試11
exists(select 1 from salebilldetail d where d.tid=260434 and d.billid=i.billid and ((match(d.remarks,d.goodsremarks) Against(concat('"','葡萄','"') in boolean mode))))

執(zhí)行時間無限長(跑了半天沒成功)?
經(jīng)分析,在 where 子句中,一個條件子句中包含一個以上 match 時會出現(xiàn)這樣的情況。即:

-- and 中只有一個全文檢索時正常, 用時0.2秒
select xxx from xxx
...
and (
	exists(select 1 from salebilldetail d where d.tid=260434 and d.billid=i.billid and ((match(d.remarks,d.goodsremarks) Against(concat('"','葡萄','"') in boolean mode))))
)
...

-- 下面這樣就異常了,會慢成百上千倍,用時 160 秒, 如果有更多的 match ,會更夸張的慢下去
select xxx from xxx
...
and (
	exists(select 1 from salebilldetail d where d.tid=260434 and d.billid=i.billid and ((match(d.remarks,d.goodsremarks) Against(concat('"','葡萄','"') in boolean mode))))
	or match(i.billno) against(concat('"','葡萄','"') in boolean mode)
)
...

測試結(jié)果匯總

查詢 用時(秒) 備注
test 1 0.765 原始like查詢
test 2 0.834 全文索引 remarks_fulltext、goodsremarks_fulltext
test 3 0.242 全文索引 remarks_goodsremarks_fulltext
---
test 4 22.654 原始like查詢,不過濾 tid
test 5 24.855 全文索引 remarks_fulltext、goodsremarks_fulltext, 不過濾 tid
test 6 0.213 全文索引 remarks_goodsremarks_fulltext, 不過濾 tid
---
test 7 0.22 全文索引 remarks_goodsremarks_fulltext, count
test 8 0.007 全文索引 remarks_goodsremarks_fulltext, 不過濾 tid, count
---
test 9 1.6 業(yè)務(wù)測試SQL,原始like查詢
test 10 1.6 業(yè)務(wù)測試SQL,全文索引 remarks_fulltext、goodsremarks_fulltext
test 11 失敗 業(yè)務(wù)測試SQL,全文索引 remarks_goodsremarks_fulltext

五、MySQL 版本升級

因線上系統(tǒng)目前是 RDS MySQL 5.6,故簡單描述升級相關(guān)問題。

參考:
MySQL 5.6,5.7,8.0新特性
MySQL最新版8.0與5.7之性能對比

  • Group By: 在 MySQL 5.7 之后,默認(rèn)使用增加了限制,一些在 MySQL 5.6 可執(zhí)行的Group By語句,在 5.7 之后會報錯,可以更改新版本 MySQL 的 sqlModel

    • 方式1:重啟 MySQL 后失效
    -- 查詢 sql_mode
    select @@SESSION.sql_mode;
    -- 設(shè)置
    SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
    -- 或 設(shè)置 (修改于當(dāng)前會 話,關(guān)閉當(dāng)前會話后失效)
    SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
    -- 刷新
    flush PRIVILEGES;
    
    
    • 方式2:在配置文件中添加 sql_mode = '對應(yīng)需要的模式'
    • sql_mode 模式說明:
      • ONLY_FULL_GROUP_BY: 對于GROUP BY聚合操作,如果在SELECT中的列,沒有在GROUP BY中出現(xiàn),那么這個SQL是不合法的,因為列不在GROUP BY從句中
      • NO_AUTO_VALUE_ON_ZERO: 該值影響自增長列的插入。默認(rèn)設(shè)置下,插入0NULL代表生成下一個自增長值。如果用戶希望插入的值為0,而該列又是自增長的,那么這個選項就有用了。
      • STRICT_TRANS_TABLES:在該模式下,如果一個值不能插入到一個事務(wù)中,則中斷當(dāng)前的操作,對非事務(wù)表不做限制
      • NO_ZERO_IN_DATE:在嚴(yán)格模式下,不允許日期和月份為零
      • NO_ZERO_DATE:設(shè)置該值,mysql數(shù)據(jù)庫不允許插入零日期,插入零日期會拋出錯誤而不是警告
      • ERROR_FOR_DIVISION_BY_ZERO:在insertupdate過程中,如果數(shù)據(jù)被零除,則產(chǎn)生錯誤而非警告。如果未給出該模式,那么數(shù)據(jù)被零除時MySql返回NULL
      • NO_AUTO_CREATE_USER: 禁止GRANT創(chuàng)建密碼為空的用戶
      • NO_ENGINE_SUBSTITUTION:如果需要的存儲引擎被禁用或未編譯,那么拋出錯誤。不設(shè)置此值時,用默認(rèn)的存儲引擎替代,并拋出一個異常
      • PIPES_AS_CONCAT:將"||"視為字符串的連接操作符而非或運算符,這和Oracle數(shù)據(jù)庫是一樣是,也和字符串的拼接函數(shù)Concat想類似
      • ANSI_QUOTES:啟用后,不能用雙引號來引用字符串,因為它被解釋為識別符

  • MySQL8.0 修改了賬號密碼加密策略 (默認(rèn)的認(rèn)證插件由mysql_native_password更改為caching_sha2_password),導(dǎo)致一些可視化軟件無法連接 mysql8.0 版本的數(shù)據(jù)庫。如果需要,可以修改默認(rèn)的策略或者賬號密碼的認(rèn)證策略

    • 方式1:配置文件中添加, 讓mysql使用原密碼策略 (需重啟mysql服務(wù))
    [mysqld]
    default_authentication_plugin = mysql_native_password
    
    • 方式2:執(zhí)行語句修改某賬號密碼驗證策略
    -- 修改加密規(guī)則 
    ALTER USER 'root'@'localhost' IDENTIFIED BY 'password' PASSWORD EXPIRE NEVER; 
    -- 更新用戶密碼
    ALTER USER '賬號'@'%' IDENTIFIED WITH mysql_native_password BY '密碼';
    -- 刷新權(quán)限
    FLUSH PRIVILEGES;
    
  • MySQL8.0 授權(quán)用戶賬號語法變更,創(chuàng)建用戶的操作已經(jīng)不支持grant的同時創(chuàng)建用戶方式,需要先創(chuàng)建用戶再進(jìn)行授權(quán)。

    -- 原來的流程:
    mysql> grant all on *.* to 'admin'@'%' identified by 'admin';
    -- 新的正確流程:
    mysql> create user 'admin'@'%' identified by 'admin';
    mysql> grant all on *.* to 'admin'@'%' ;
    mysql> flush privileges;
    
  • 數(shù)據(jù)庫連接區(qū)別

    • JDBC 連接串修改如下(首先需要驅(qū)動使用8.0對應(yīng)連接的驅(qū)動):
    jdbc:mysql://{ip}:{port}/{db}&#63;characterEncoding=utf8&useSSL=false&serverTimezone=UTC
    // useSSL  如果不配置false 項目可以正常啟動但是會提示ssl問題
    // serverTimezone=UTC 必須配置【時區(qū)設(shè)置成自己對應(yīng)的時區(qū)】否則項目會報錯
    
    
    • 如果時區(qū)問題還不能解決:
    show variables like '%time_zone%';
    set global time_zone='+8:00';
    
  • MySQL 5.7 原生支持JSON類型,并引入了眾多JSON函數(shù)

  • MySQL 8.0 JSON字段的部分更新(JSON Partial Updates)

  • MySQL 8.0 默認(rèn)字符集由latin1修改為utf8mb4

  • MySQL 8.0 正則表達(dá)式的增強(qiáng),新增了4個相關(guān)函數(shù),REGEXP_INSTR(),REGEXP_LIKE(),REGEXP_REPLACE(),REGEXP_SUBSTR()

  • MySQL 8.0 GROUP BY語句不再隱式排序 (忽略在Group By中的排序命令,如 desc, asc)

END

本文摘自 :https://www.cnblogs.com/

開通會員,享受整站包年服務(wù)立即開通 >