[英]MySQL Character Set & Select Query Performance in stored procedure
最近我注意到很少有查詢在執行時花費很長時間,進一步檢查發現 MySQL 優化器正在嘗試在Where
子句中使用 COLLATE,這會導致性能問題,如果我在沒有 COLLATE 的查詢下運行然后從數據庫中得到快速響應:
SELECT notification_id FROM notification
WHERE ref_table = 2
AND ref_id = NAME_CONST('v_wall_detail_id',_utf8mb4'c37e32fc-b3b5-11ec-befc-02447a44a47c' COLLATE 'utf8mb4_unicode_ci')
MySQL 版本 5.7
Database Character Set: utf8mb4
Column Character set: UTF8
Column Data Type: CHAR(36) UUID
From PHP in Connection object passing: utf8mb4
Index is applied
This query is written in MySQL stored procedure
顯示創建表
CREATE TABLE `notification` (
`notification_id` CHAR(36) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`title` VARCHAR(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`notification_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4
顯示像“coll%”這樣的變量;
collation_connection utf8_general_ci
collation_database utf8mb4_unicode_ci
collation_server latin1_swedish_ci
顯示像“char%”這樣的變量;
character_set_client, Connection,Result, System: utf8
character_set_database utf8mb4
character_set_server latin1
character_set_system utf8
任何建議,需要哪些改進才能使我的查詢更快?
該表的字符集是 utf8,所以我猜它的排序規則是 utf8_general_ci 或 utf8_unicode_ci 之一。 你可以這樣檢查:
SELECT collation_name from INFORMATION_SCHEMA.COLUMNS
WHERE table_schema = '...your schema...' AND table_name = 'notification'
AND column_name = 'ref_id';
您強迫它與具有 utf8mb4 字符集和排序規則的字符串進行比較。 索引是一種排序的數據結構,排序順序取決於列的排序規則。 使用該索引意味着利用排序順序快速查找值,而無需檢查每一行。
當您將該列與具有不同排序規則的字符串進行比較時,MySQL 無法推斷出您的 UUID 常量的排序順序或字符串等效性是兼容的。 所以它必須以困難的方式逐行進行字符串比較。
這不是錯誤,這是排序規則工作的預期方式。 要利用索引,您必須與具有兼容排序規則的字符串進行比較。
我測試發現以下表達式無法使用索引:
不同的字符集,不同的排序規則:
WHERE ref_id = _utf8mb4'c37e32fc-b3b5-11ec-befc-02447a44a47c' COLLATE utf8mb4_general_ci
WHERE ref_id = _utf8mb4'c37e32fc-b3b5-11ec-befc-02447a44a47c' COLLATE utf8mb4_unicode_ci
相同的字符集,不同的排序規則:
WHERE ref_id = _utf8'c37e32fc-b3b5-11ec-befc-02447a44a47c' COLLATE 'utf8_unicode_ci'
以下表達式成功使用索引:
不同字符集,默認排序規則:
WHERE ref_id = _utf8mb4'c37e32fc-b3b5-11ec-befc-02447a44a47c'
相同的字符集,相同的排序規則:
WHERE ref_id = _utf8'c37e32fc-b3b5-11ec-befc-02447a44a47c' COLLATE 'utf8_general_ci'
相同的字符集,默認排序規則:
WHERE ref_id = _utf8'c37e32fc-b3b5-11ec-befc-02447a44a47c'
為了簡化您的環境,我建議您在所有表和 session 中只使用一種字符集和一種排序規則。我建議:
ALTER TABLE notification CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
這將使用指定排序規則的排序順序重建字符串列的索引。
然后使用COLLATE utf8mb4_unicode_ci
將兼容,並將使用索引。
PS 在所有情況下,我都省略了 NAME_CONST() function,因為據我所知,它在 WHERE 子句中沒有任何作用。 我不知道你為什么要用它。
這些說明客戶在說什么:
collation_connection utf8_general_ci
character_set_client, Connection,Result, System: utf8
要么更改它們,要么更改各個列以匹配它們。
如果您有存儲例程,則需要刪除它們,執行SET NAMES
以匹配您選擇的內容,然后重新創建。
由於您使用的是 5.7,因此我建議始終使用utf8mb4
和utf8mb4_unicode_520_ci
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.