• SQL优化之【类型转换】


    DBA的日常工作中SQL优化占大半的时间,通常都是SQL语句性能问题或者schema设计有问题,最近遇到一个类型转换的问题,所以在这里分享一下,废话不多说了,直接建表进行测试。

    mysql> create table t1 ( id int , name char(20), key ( id) );
    Query OK, 0 rows affected (0.02 sec)
    
    mysql> insert into t1 select 1,'aa';
    Query OK, 1 row affected (0.00 sec)
    Records: 1  Duplicates: 0  Warnings: 0
    
    mysql> insert into t1 select 2,'bb';
    Query OK, 1 row affected (0.00 sec)
    Records: 1  Duplicates: 0  Warnings: 0
    
    mysql> create table t2 select * from t1;
    Query OK, 2 rows affected (0.03 sec)
    Records: 2  Duplicates: 0  Warnings: 0
    
    mysql> 

    进行查询测试:

    mysql> explain select a.id from t1 as a inner join t2 as b on a.id=b.id;  
    +----+-------------+-------+-------+---------------+------+---------+------+------+--------------------------------+
    | id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra                          |
    +----+-------------+-------+-------+---------------+------+---------+------+------+--------------------------------+
    |  1 | SIMPLE      | a     | index | id            | id   | 5       | NULL |    2 | Using index                    |
    |  1 | SIMPLE      | b     | ALL   | NULL          | NULL | NULL    | NULL |    2 | Using where; Using join buffer |
    +----+-------------+-------+-------+---------------+------+---------+------+------+--------------------------------+

    这什么情况?出现了Using join buffer,那是因为我们在创建t2表的时候直接使用了create table xxx select * from xxx,这种创建表且带数据的方法会去掉索引。我们看看表结构:

    mysql> show create table t2G
    *************************** 1. row ***************************
           Table: t2
    Create Table: CREATE TABLE `t2` (
      `id` int(11) DEFAULT NULL,
      `name` char(20) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    1 row in set (0.00 sec)
    
    mysql> 

    可以看见id上面的索引不在了,加上索引回归主题进行测试。

    mysql> alter table t2 add key(id);
    Query OK, 0 rows affected (0.03 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> 

    再次进行join查询:

    mysql> explain select a.id from t1 as a inner join t2 as b on a.id=b.id;
    +----+-------------+-------+-------+---------------+------+---------+-----------+------+--------------------------+
    | id | select_type | table | type  | possible_keys | key  | key_len | ref       | rows | Extra                    |
    +----+-------------+-------+-------+---------------+------+---------+-----------+------+--------------------------+
    |  1 | SIMPLE      | a     | index | id            | id   | 5       | NULL      |    2 | Using index              |
    |  1 | SIMPLE      | b     | ref   | id            | id   | 5       | test.a.id |    1 | Using where; Using index |
    +----+-------------+-------+-------+---------------+------+---------+-----------+------+--------------------------+
    2 rows in set (0.00 sec)
    
    mysql> 

    可以看见上面的执行计划是正确的,没有异常,那么何时出现类型转换呢?很简单,我们把t2表的id字段改成字符串就行。

    mysql> alter table t2 modify id char(20);
    Query OK, 2 rows affected (0.06 sec)
    Records: 2  Duplicates: 0  Warnings: 0
    
    mysql> 
    mysql> explain select a.id from t1 as a inner join t2 as b on a.id=b.id;
    +----+-------------+-------+-------+---------------+------+---------+------+------+---------------------------------------------+
    | id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra                                       |
    +----+-------------+-------+-------+---------------+------+---------+------+------+---------------------------------------------+
    |  1 | SIMPLE      | a     | index | id            | id   | 5       | NULL |    2 | Using index                                 |
    |  1 | SIMPLE      | b     | index | id            | id   | 61      | NULL |    2 | Using where; Using index; Using join buffer |
    +----+-------------+-------+-------+---------------+------+---------+------+------+---------------------------------------------+
    2 rows in set (0.00 sec)
    
    mysql> 

    很明显执行计划变化了,在数据量少或者执行少的情况下还好,如果并发大,或者数据量大,那么这将是一个灾难,这也是有时候我们在优化SQL的时候,发现索引都有,执行计划就是不对,那么你就应该看看是否出现了类型转换。

  • 相关阅读:
    bzoj 1715: [Usaco2006 Dec]Wormholes 虫洞【spfa判负环】
    bzoj 1627: [Usaco2007 Dec]穿越泥地【bfs】
    bzoj 1596: [Usaco2008 Jan]电话网络【贪心】
    bzoj 1624: [Usaco2008 Open] Clear And Present Danger 寻宝之路【Floyd】
    bzoj 1629: [Usaco2007 Demo]Cow Acrobats【贪心+排序】
    bzoj 1639: [Usaco2007 Mar]Monthly Expense 月度开支【二分】
    bzoj 1708: [Usaco2007 Oct]Money奶牛的硬币
    bzoj 1827: [Usaco2010 Mar]gather 奶牛大集会【树形dp】
    bzoj 1576: [Usaco2009 Jan]安全路经Travel【spfa+树链剖分+线段树】
    bzoj 1592: [Usaco2008 Feb]Making the Grade 路面修整【dp】
  • 原文地址:https://www.cnblogs.com/gomysql/p/4450928.html
Copyright © 2020-2023  润新知