• 在数据库查询中不走索引的情况与压力测试


    重点关注:

    1) 没有查询条件,或者查询条件没有建立索引

    例如:

    select * from tab; 全表扫描。
    select * from tab where 1=1;

    在业务数据库中,特别是数据量比较大的表。
    是没有全表扫描这种需求。  

      1、对用户查看是非常痛苦的。
      2、对服务器来讲毁灭性的。

    例如:

    select * from tab;
    SQL改写成以下语句:
    selec  * from tab  order by  price  limit 10      需要在price列上建立索引
    select  * from  tab where name='zhangsan'          name列没有索引
    
    改:
        1、换成有索引的列作为查询条件
        2、将name列建立索引

    2) 查询结果集是原表中的大部分数据,应该是25%以上。

    查询的结果集,超过了总数行数25%,优化器觉得就没有必要走索引了。

    假如:

    tab表 id,name id:1-100w ,id列有索引

    select * from tab where id>500000;

    如果业务允许,可以使用limit控制。

    怎么改写 ?
    结合业务判断,有没有更好的方式。如果没有更好的改写方案
    尽量不要在mysql存放这个数据了。放到redis里面。

    3) 索引本身失效,统计数据不真实

    索引有自我维护的能力。
    对于表内容变化比较频繁的情况下,有可能会出现索引失效。

    4) 查询条件使用函数在索引列上,或者对索引列进行运算,运算包括(+,-,*,/,! 等)

    例子:

    错误的例子:select * from test where id-1=9; 
    正确的例子:select * from test where id=10;

    算术运算
    函数运算

    desc select * from blog_userinfo where DATE_FORMAT(last_login,'%Y-%m-%d') >= '2019-01-01';

    子查询

    5)隐式转换导致索引失效.这一点应当引起重视.也是开发中经常会犯的错误. 

    select * from t1 where telnum=110;
    
    
    这样会导致索引失效. 错误的例子:
    ------------------------
    mysql> alter table tab add index inx_tel(telnum);
    Query OK, 0 rows affected (0.03 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> 
    mysql> desc tab;
    +--------+-------------+------+-----+---------+-------+
    | Field  | Type        | Null | Key | Default | Extra |
    +--------+-------------+------+-----+---------+-------+
    | id     | int(11)     | YES  |     | NULL    |       |
    | name   | varchar(20) | YES  |     | NULL    |       |
    | telnum | varchar(20) | YES  | MUL | NULL    |       |
    +--------+-------------+------+-----+---------+-------+
    3 rows in set (0.01 sec)
    
    
    mysql> select * from tab where telnum='1333333';
    +------+------+---------+
    | id   | name | telnum  |
    +------+------+---------+
    |    1 | a    | 1333333 |
    +------+------+---------+
    1 row in set (0.00 sec)
    
    mysql> select * from tab where telnum=1333333;
    +------+------+---------+
    | id   | name | telnum  |
    +------+------+---------+
    |    1 | a    | 1333333 |
    +------+------+---------+
    1 row in set (0.00 sec)
    
    mysql> explain  select * from tab where telnum='1333333';
    +----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
    | id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra                 |
    +----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
    |  1 | SIMPLE      | tab   | ref  | inx_tel       | inx_tel | 63      | const |    1 | Using index condition |
    +----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
    1 row in set (0.00 sec)
    
    mysql> explain  select * from tab where telnum=1333333;
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    |  1 | SIMPLE      | tab   | ALL  | inx_tel       | NULL | NULL    | NULL |    2 | Using where |
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    1 row in set (0.00 sec)
    
    
    mysql> explain  select * from tab where telnum=1555555;
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    |  1 | SIMPLE      | tab   | ALL  | inx_tel       | NULL | NULL    | NULL |    2 | Using where |
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    1 row in set (0.00 sec)
    
    mysql> explain  select * from tab where telnum='1555555';
    +----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
    | id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra                 |
    +----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
    |  1 | SIMPLE      | tab   | ref  | inx_tel       | inx_tel | 63      | const |    1 | Using index condition |
    +----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
    1 row in set (0.00 sec)
    
    mysql> 
    
    ---------------------------------------

    6) <>  ,not in 不走索引

    EXPLAIN SELECT * FROM teltab WHERE telnum   <> '110';
    EXPLAIN  SELECT * FROM teltab WHERE telnum  NOT IN ('110','119');
    ------------
    mysql> select * from tab where telnum <> '1555555';
    +------+------+---------+
    | id   | name | telnum  |
    +------+------+---------+
    |    1 | a    | 1333333 |
    +------+------+---------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from tab where telnum <> '1555555';
    
    
    -----
    单独的>,<,in 有可能走,也有可能不走,和结果集有关,尽量结合业务添加limit
    or或in  尽量改成union
    
    EXPLAIN  SELECT * FROM teltab WHERE telnum   IN ('110','119');
    改写成:
    
    EXPLAIN SELECT * FROM teltab WHERE telnum='110'
    UNION ALL
    SELECT * FROM teltab WHERE telnum='119'
    
    -----------------------------------

    7)   like "%_" 百分号在最前面不走

    EXPLAIN SELECT * FROM teltab WHERE telnum LIKE '31%'   走range索引扫描
    
    EXPLAIN SELECT * FROM teltab WHERE telnum LIKE '%110'  不走索引
    
    
    %linux%类的搜索需求,可以使用elasticsearch 专门做搜索服务的数据库产品

    8) 单独引用联合索引里非第一位置的索引列.作为条件查询时不走索引.

    列子:
    复合索引:
    
    DROP TABLE t1
    CREATE TABLE t1 (id INT,NAME VARCHAR(20),age INT ,sex ENUM('m','f'),money INT);
    
    ALTER TABLE t1 ADD INDEX t1_idx(money,age,sex);
    
    DESC t1
    SHOW INDEX FROM t1
    
    走索引的情况测试:
    EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND age=30  AND sex='m';
    EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND age=30  ;
    EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30  AND sex='m';    ----->部分走索引
    不走索引的:
    EXPLAIN SELECT  NAME,age,sex,money FROM t1 WHERE  age=20
    EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE  age=30  AND sex='m';
    EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE   sex='m';

    压力测试

    1、模拟数据库数据

    为了测试我们创建一个oldboy的库创建一个t1的表,然后导入50万行数据,脚本如下:

    vim slap.sh
    #!/bin/bash  
    HOSTNAME="localhost" 
    PORT="3306" 
    USERNAME="root" 
    PASSWORD="123" 
    DBNAME="oldboy" 
    TABLENAME="t1" 
    #create database 
    mysql -h ${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} -e "drop database if exists ${DBNAME}" 
    create_db_sql="create database if not exists ${DBNAME}" 
    mysql -h ${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} -e "${create_db_sql}" 
    #create table 
    create_table_sql="create table if not exists ${TABLENAME}(stuid int not null primary key,stuname varchar(20) not null,stusex char(1)   
    not null,cardid varchar(20) not null,birthday datetime,entertime datetime,address varchar(100)default null)" 
    mysql -h ${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} ${DBNAME} -e "${create_table_sql}" 
    #insert data to table 
    i="1" 
    while [ $i -le 500000 ]  
    do  
    insert_sql="insert into ${TABLENAME}  values($i,'alexsb_$i','1','110011198809163418','1990-05-16','2017-09-13','oldboyedu')" 
    mysql -h ${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} ${DBNAME} -e "${insert_sql}" 
    let i++  
    done  
    #select data  
    select_sql="select count(*) from ${TABLENAME}" 
    mysql -h ${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} ${DBNAME} -e "${select_sql}"

    执行脚本:
    sh slap.sh

    2、检查数据可用性

    mysql -uroot -p123
    select count(*) from oldboy.t1;

    3、在没有优化之前我们使用mysqlslap来进行压力测试

    mysqlslap --defaults-file=/etc/my.cnf 
     --concurrency=100 --iterations=1 --create-schema='oldboy' 
    --query="select * from oldboy.t1 where stuname='alexsb_100'" engine=innodb 
    --number-of-queries=2000 -uroot -p123 -verbose
  • 相关阅读:
    Android Studio使用百度地图(二)
    Android Studio使用百度地图(一)
    寒假每日日报30(体温登记app——进度3)
    EF CodeFirst数据注解特性详解
    EF CodeFirst配置领域类
    EF CodeFirst简介、默认约定、数据库初始化策略
    EF CodeFirst关于Mysql如何自动生成数据库表
    EF的预先加载--Eager Loading
    EF的延迟加载LazyLoad
    ADO.NET中sqlserver和mysql的变量名
  • 原文地址:https://www.cnblogs.com/zhaijihai/p/10274913.html
Copyright © 2020-2023  润新知