Mysql中where條件一個單引號引發的性能損耗


日常寫SQL中可能會有一些小細節忽略了導致整個sql的性能下降了好幾倍甚至幾十倍,幾百倍。以下這個示例就是mysql語句中的一個單引號('')引發的性能耗損,我相信很多朋友都遇到過,甚至還在這樣寫。

先看下我的表結構:

CREATE TABLE `d_sku` (
  `id` varchar(36) NOT NULL,
  `commodity_id` varchar(36) DEFAULT NULL,
  `counts` int(11) DEFAULT NULL,
  `price` double(15,2) DEFAULT NULL,
  `status` int(11) DEFAULT NULL,
  `location` varchar(100) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  `create_id` varchar(36) DEFAULT NULL,
  `modify_time` datetime DEFAULT NULL,
  `provalue_str` varchar(500) DEFAULT NULL,
  `category_id` varchar(36) DEFAULT NULL,
  `customer_id` varchar(36) DEFAULT NULL,
  `cert_no` varchar(100) DEFAULT NULL,
  `profit` double DEFAULT NULL,
  `check_cargo` int(11) DEFAULT '0',
  `check_time` datetime DEFAULT NULL,
  `keep_last_checked` int(11) DEFAULT NULL,
  `approval_status` int(11) DEFAULT '0',
  `code` varchar(30) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_price` (`price`) USING BTREE,
  KEY `index_category_status` (`category_id`,`status`) USING BTREE,
  KEY `index_modifytime` (`modify_time`) USING BTREE,
  KEY `index_customerId_categoryId` (`customer_id`,`category_id`) USING BTREE,
  KEY `index_certNo_customerId` (`cert_no`,`customer_id`) USING BTREE,
  KEY `index_provaluestr` (`provalue_str`(320)) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC

一個電商平台的SKU數據庫表結構模式,該表中數據條數376138。以此下兩種查詢方式看下執行效率。查詢語句都是從該表中查詢一條數據分類為d2a17030-149d-11e5-a9de-000c29d7a3a0並且編號為5186354366的數據。

1.實例測試

1.對查詢內容添加單引號

SELECT * FROM d_sku d where category_id='d2a17030-149d-11e5-a9de-000c29d7a3a0' and  d.cert_no='5186354366';

【消息】:執行成功,當前返回:[1]行,耗時:[1ms.]。查詢速度非常快。

2.對查詢內容不添加單引號

SELECT * FROM d_sku d where category_id='d2a17030-149d-11e5-a9de-000c29d7a3a0' and  d.cert_no=5186354366;

【消息】:執行成功,當前返回:[1]行,耗時:[1210ms.]發現兩者之間的執行效率顯而易見啊。

 2.兩者區別分析

這樣一查詢效果真的是顯而易見,添加單引號查詢才1ms,不添加單引號查詢的耗時是1210ms.一條數據就這么明顯了。可想而知這種性能損失有多大。但是為什么會這樣呢?先從分析索引看起。使用關鍵詞 “explain” 查看sql執行效率詳細(關鍵詞使用介紹點傳送門)。

explain  SELECT * FROM d_sku d where category_id='d2a17030-149d-11e5-a9de-000c29d7a3a0' and  d.cert_no='5186354366';

explain  SELECT * FROM d_sku d where category_id='d2a17030-149d-11e5-a9de-000c29d7a3a0' and  d.cert_no=5186354366;

 

圖一:添加單引號

圖二:未添加單引號

兩條數據對比分析:

圖一:

添加單引號后的性能詳情,其中表頭key這里顯示出來真正使用了組合索引“index_certNo_customerId” ,其中這兩個索引對應的列正好是“category_id”和“cert_no”。再看rows這,表示查詢這條數據只檢索了一條數據,因為是這里索引生效了,所以通過“cert_no”編號直接查詢到了數據。

圖二:

未添加單引號后的性能詳情,發現真正使用的索引只有“index_category_status”,回到創建表結構的時候可以發現這條索引信息是添加`category_id`,`status`這兩個列的,表示只用到了category_id,而第二個條件的cert_no列並沒有用到索引,所以性能的損耗就在這里發生了。

總結:

原因就是因為我們創建表結構的時候cert_no字段是varchar類型的,而where時未添加單引號的時候參數是被做為數字類型來使用的,那不同的類型做查詢的時候肯定是要轉型的,數據類型轉換的話就無法正常使用索引了。所以可以得到一個結論就是Int類型的數據在轉換varchar再使用是不會使用索引的。我們可以修改表結構將cert_no改為int類型后在使用不添加單引號的參數查詢時性能也就是正常的了。同樣也是可以通過添加單引號來實現。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM