转自http://www.cnblogs.com/billyxp/archive/2013/05/31/3110016.html

最近一周接连处理了2个由于int向varchar转换无法使用索引,从而引发的慢查询。

  1. CREATE TABLE `appstat_day_prototype_201305` (
  2. `day_key` date NOT NULL DEFAULT '1900-01-01',
  3. `appkey` varchar(20) NOT NULL DEFAULT '',
  4. `user_total` bigint(20) NOT NULL DEFAULT '0',
  5. `user_activity` bigint(20) NOT NULL DEFAULT '0',
  6. `times_total` bigint(20) NOT NULL DEFAULT '0',
  7. `times_activity` bigint(20) NOT NULL DEFAULT '0',
  8. `incr_login_daily` bigint(20) NOT NULL DEFAULT '0',
  9. `unbind_total` bigint(20) NOT NULL DEFAULT '0',
  10. `unbind_activitys` bigint(20) NOT NULL DEFAULT '0',
  11. PRIMARY KEY (`appkey`,`day_key`)
  12. ) ENGINE=InnoDB DEFAULT CHARSET=utf8
  13.  
  14. mysql> explain SELECT * from appstat_day_prototype_201305 where appkey = xxxxx and day_key between '2013-05-23' and '2013-05-30';
  15. +----+-------------+------------------------------+------+---------------+------+---------+------+----------+-------------+
  16. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  17. +----+-------------+------------------------------+------+---------------+------+---------+------+----------+-------------+
  18. | 1 | SIMPLE | appstat_day_prototype_201305 | ALL | PRIMARY | NULL | NULL | NULL | 19285787 | Using where |
  19. +----+-------------+------------------------------+------+---------------+------+---------+------+----------+-------------+
  20. 1 row in set (0.00 sec)
  21.  
  22. mysql> explain SELECT * from appstat_day_prototype_201305 where appkey = 'xxxxx' and day_key between '2013-05-23' and '2013-05-30';
  23. +----+-------------+------------------------------+-------+---------------+---------+---------+------+------+-------------+
  24. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  25. +----+-------------+------------------------------+-------+---------------+---------+---------+------+------+-------------+
  26. | 1 | SIMPLE | appstat_day_prototype_201305 | range | PRIMARY | PRIMARY | 65 | NULL | 1 | Using where |
  27. +----+-------------+------------------------------+-------+---------------+---------+---------+------+------+-------------+
  28. 1 row in set (0.00 sec)

从上面可以很明显的看到由于appkey是varchar,而在where条件中不加'',会引发全表查询,加了就可以用到索引,这扫描的行数可是天差地别,对于服务器的压力和响应时间自然也是天差地别的。

我们再看另外一个例子:

  1. *************************** 1. row ***************************
  2. Table: poll_joined_151
  3. Create Table: CREATE TABLE `poll_joined_151` (
  4. `poll_id` bigint(11) NOT NULL,
  5. `uid` bigint(11) NOT NULL,
  6. `item_id` varchar(60) NOT NULL,
  7. `add_time` int(11) NOT NULL DEFAULT '0',
  8. `anonymous` tinyint(1) NOT NULL DEFAULT '0',
  9. `sub_item` varchar(1200) NOT NULL DEFAULT '',
  10. KEY `idx_poll_id_uid_add_time` (`poll_id`,`uid`,`add_time`),
  11. KEY `idx_anonymous_id_addtime` (`anonymous`,`poll_id`,`add_time`)
  12. ) ENGINE=InnoDB DEFAULT CHARSET=utf8
  13.  
  14. SELECT * FROM poll_joined_151 WHERE poll_id = '2348993' AND anonymous =0 ORDER BY add_time DESC LIMIT 0 , 3
  15.  
  16. *************************** 1. row ***************************
  17. id: 1
  18. select_type: SIMPLE
  19. table: poll_joined_151
  20. type: ref
  21. possible_keys: idx_poll_id_uid_add_time,idx_anonymous_id_addtime
  22. key: idx_anonymous_id_addtime
  23. key_len: 9
  24. ref: const,const
  25. rows: 30240
  26. Extra: Using where

从上面的例子看,虽然poll_id的类型为bigint,但是SQL中添加了'',但是这个语句仍然用到了索引,虽然扫描行数也不少,但是能用到索引就是好SQL。

那么一个小小的''为什么会有这么大的影响呢?根本原因是因为MySQL在对文本类型和数字类型进行比较的时候会进行隐式的类型转换。以下是5.5官方手册的说明:

  1. If both arguments in a comparison operation are strings, they are compared as strings.
  2. 两个参数都是字符串,会按照字符串来比较,不做类型转换。
  3. If both arguments are integers, they are compared as integers.
  4. 两个参数都是整数,按照整数来比较,不做类型转换。
  5. Hexadecimal values are treated as binary strings if not compared to a number.
  6. 十六进制的值和非数字做比较时,会被当做二进制串。
  7. If one of the arguments is a TIMESTAMP or DATETIME column and the other argument is a constant, the constant is converted to a timestamp before the comparison is performed. This is done to be more ODBC-friendly. Note that this is not done for the arguments to IN()! To be safe, always use complete datetime, date, or time strings when doing comparisons. For example, to achieve best results when using BETWEEN with date or time values, use CAST() to explicitly convert the values to the desired data type.
  8. 有一个参数是 TIMESTAMP DATETIME,并且另外一个参数是常量,常量会被转换为 timestamp
  9. If one of the arguments is a decimal value, comparison depends on the other argument. The arguments are compared as decimal values if the other argument is a decimal or integer value, or as floating-point values if the other argument is a floating-point value.
  10. 有一个参数是 decimal 类型,如果另外一个参数是 decimal 或者整数,会将整数转换为 decimal 后进行比较,如果另外一个参数是浮点数,则会把 decimal 转换为浮点数进行比较
  11. In all other cases, the arguments are compared as floating-point (real) numbers.
    所有其他情况下,两个参数都会被转换为浮点数再进行比较

根据以上的说明,当where条件之后的值的类型和表结构不一致的时候,MySQL会做隐式的类型转换,都将其转换为浮点数在比较。

对于第一种情况:

比如where string = 1;

需要将索引中的字符串转换成浮点数,但是由于'1',' 1','1a'都会比转化成1,故MySQL无法使用索引只能进行全表扫描,故造成了慢查询的产生。

  1. mysql> SELECT CAST(' 1' AS SIGNED)=1;
  2. +-------------------------+
  3. | CAST(' 1' AS SIGNED)=1 |
  4. +-------------------------+
  5. | 1 |
  6. +-------------------------+
  7. 1 row in set (0.00 sec)
  8.  
  9. mysql> SELECT CAST(' 1a' AS SIGNED)=1;
  10. +--------------------------+
  11. | CAST(' 1a' AS SIGNED)=1 |
  12. +--------------------------+
  13. | 1 |
  14. +--------------------------+
  15. 1 row in set, 1 warning (0.00 sec)
  16.  
  17. mysql> SELECT CAST('1' AS SIGNED)=1;
  18. +-----------------------+
  19. | CAST('1' AS SIGNED)=1 |
  20. +-----------------------+
  21. | 1 |
  22. +-----------------------+
  23. 1 row in set (0.00 sec)

同时需要注意一点,由于都会转换成浮点数进行比较,而浮点数只有53bit,故当超过最大值的时候,比较会出现问题。

对于第二种情况:

由于索引建立在int的基础上,而将纯数字的字符串可以百分百转换成数字,故可以使用到索引,虽然也会进行一定的转换,消耗一定的资源,但是最终仍然使用了索引,不会产生慢查询。

  1. mysql> select CAST( '30' as SIGNED) = 30;
  2. +----------------------------+
  3. | CAST( '30' as SIGNED) = 30 |
  4. +----------------------------+
  5. | 1 |
  6. +----------------------------+
  7. 1 row in set (0.00 sec)

【转】MySQL int转换成varchar引发的慢查询的更多相关文章

  1. SQL中DateTime转换成Varchar样式

    SQL中DateTime转换成Varchar样式语句及查询结果:Select CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AMSelect ...

  2. MySql Int 类型和 varchar类型进行比较。

    今天遇到个比较奇葩的问题,简单讲就是在Mysql中进行查询的时候 在Where语句中使用的int类型的字段和Varchar类型的字段进行对比. 例如:我这有一张表: 表中的数据如下: 当我进行查询的时 ...

  3. C#中如何把int转换成两个字符的string

    部门新开了项目,所以一整周的时间都在瞎忙,为什么称瞎忙?所负责的内容,并没有做好,也是一万个心塞啊.... 说一下最近碰到的一些问题. 用到了计时,但是比如定时是一分半钟,可是显示的时候,想让显示为1 ...

  4. flask框架下读取mysql数据 转换成json格式API

    研究了一天 因为需要从数据库拿数据然后转换成json的格式 expose出去为 API 发现一条数据是容易,两条以上我居然搞了这么久 好歹出来了 先贴一下 后面更新 mysql的操作 比较容易了htt ...

  5. Mysql 表转换成 Sqlite表

    目前的转换仅仅支持对没有外键的Mysql数据表 准备: 下载安装 Sqlite Expert 软件 一 获取Mysql中的.sql文件,获取过程省略可以直接导出sql文件 二 在Sqlite Expe ...

  6. mysql时间戳转换成可读时间格式

    代码: SELECT FROM_UNIXTIME(1234567890, '%Y-%m-%d %H:%i:%S') 附:在mysql中,一个时间字段的存储类型是int(11),怎么转化成字符类型,比方 ...

  7. SqlServer将日期格式DateTime转换成varchar类型

    Select CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AM Select CONVERT(varchar(100), GETDATE( ...

  8. int 转换成 CString(VC2008里有这个问题)

    int s = 123; CString str; str.Format("%d",s); 这样就可以了,但是有的会提示这个错误 如果出现这个错误,就改成下面这个就OK了:  st ...

  9. MySQL中文转换成拼音的函数

    CREATE DEFINER=`root`@`localhost` FUNCTION `fristPinyin`(`P_NAME` VARCHAR(255) CHARSET utf8) RETURNS ...

随机推荐

  1. how tomcat works 读书笔记(一)----------一个简单的web服务器

    http协议 若是两个人能正常的说话交流,那么他们间必定有一套统一的语言规则<在网络上服务器与客户端能交流也依赖与一套规则,它就是我们说的http规则(超文本传输协议Hypertext tran ...

  2. 【Visual C++】游戏编程学习笔记之一:五毛钱特效之透明和半透明处理

    本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44163799 作者:ZeeCod ...

  3. Linux下MySQL备份以及crontab定时备份

    1. 备份某个数据库 ################################################################## # 备份某个数据库 ############ ...

  4. Android WebKit 内核

    一.WebKit简介 WebKit是一个开源的浏览器网页排版引擎,包含WebCore排版引擎和JSCore引擎.WebCore和JSCore引擎来自于KDE项目的KHTML和KJS开源项目.Andro ...

  5. SpriteBuilder中同父节点的显示顺序

    如下图: 到目前为止,GameScene依赖于节点在SpriteBuilder中的顺序去决定其绘制的顺序. level content(_levelNode)被首先绘制,然后GameMenuLayer ...

  6. Mina源码阅读笔记(四)—Mina的连接IoConnector1

    上一篇写的是IoAcceptor是服务器端的接收代码,今天要写的是IoConnector,是客户端的连接器.在昨天,我们还留下一些问题没有解决,这些问题今天同样会产生,但是都要等到讲到session的 ...

  7. mybatis ---- 实现数据的增删改查

    前面介绍了接口方式的编程,需要注意的是:在book.xml文件中,<mapper namespace="com.mybatis.dao.IBookDao"> ,命名空间 ...

  8. Android 在Fragment中执行onActivityResult不被调用的简单解决方法

    在Android开发中,我们经常会用到FragmentActivity下嵌套多个Fragment,但是在开发过程中会发现在嵌套的Fragment中使用onActivityResult回调方法没有被执行 ...

  9. javap

    本词条缺少概述.信息栏.名片图,补充相关内容使词条更完整,还能快速升级,赶紧来编辑吧! javap是jdk自带的一个工具,可以反编译,也可以查看java编译器生成的字节码,是分析代码的一个好工具. j ...

  10. EF Core使用SQL调用返回其他类型的查询

    假设你想要 SQL 本身编写,而不使用 LINQ. 需要运行 SQL 查询中返回实体对象之外的内容. 在 EF Core 中,执行该操作的另一种方法是编写 ADO.NET 代码,并从 EF 获取数据库 ...