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

重点关注:

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

原文地址:https://www.cnblogs.com/zhaijihai/p/10274913.html

时间: 2024-11-05 15:53:08

在数据库查询中不走索引的情况与压力测试的相关文章

android 数据库查询中使用索引-大幅提高数据库操作速度

参考: http://blog.csdn.net/dongyuxi1987/article/details/8239739 1.数据库索引简介回忆一下小时候查字典的步骤,索引和字典目录的概念是一致的.字典目录可以让我们不用翻整本字典就找到我们需要的内容页数,然后翻到那一页就可以.索引也是一样,索引是对记录按照多个字段进行排序的一种展现.对表中的某个字段建立索引会创建另一种数据结构,其中保存着字段的值,每个值还包括指向与它相关记录的指针.这样,就不必要查询整个数据库,自然提升了查询效率.同时,索引

查询不走索引的情况

不走索引的情况还是蛮多的1.条件字段选择性弱,查出的结果集较大,不走索引:2.where条件等号两边字段类型不同,不走索引:3.优化器分析的统计信息陈旧也可能导致不走索引:4.索引字段 is null 不走索引:5.对于count(*)当索引字段有not null约束时走索引,否则不走索引:6.like 后面的字符当首位为通配符时不走索引:7.使用不等于操作符如:<>.!= 等不走索引:8.索引字段前加了函数或参加了运算不走索引:

数据库查询中的特殊字符的问题

在进行数据库的查询时,会经常遇到这样的情况: 例如想在一个用户数据库中查询他的用户名和他的密码,但恰好该用户使用的名字和密码中有特殊的字符,例如单引号,"|"号,双引号或者连字符"&". 例如他的名字是1"test,密码是A|&900 这时当你执行以下的查询语句时,肯定会报错: SQL = "SELECT * FROM SecurityLevel WHERE UID="" & UserID &

关于数据库表中的索引及索引列的CRUD

-- 查询一个数据库表中的索引及索引列use [RuPengWangDB]GOSELECT  indexname = a.name , tablename = c. name , indexcolumns = d .name , a .indidFROM    sysindexes a JOIN sysindexkeys b ON a .id = b .id  AND a .indid = b.indid        JOIN sysobjects c ON b .id = c .id    

在linux中给你的应用做压力测试

在linux中给你的应用做压力测试 作者: 立地 邮箱: [email protected] QQ: 511363759 一.webbench 1.在Ubuntu中安装webbench —支持get,head等请求,但不支持post请求 wget http://blog.zyan.cc/soft/linux/webbench/webbench-1.5.tar.gz tar zxvf webbench-1.5.tar.gz cd webbench-1.5 make && make insta

MySQL数据库查询中的特殊命令

第一:   MySQL的安装 下载MySQL软件,修改安装路径之后 安装数据库MySQL5.7.18 第一步:数据库MySQL5.7.18可以在官网上下载对应的版本,下载地址:http://www.filehorse.com/download-mysql-64/, 第二步:将下载好的安装包进行解压到一个盘下面, 第三步:配置环境变量,新建环境变量MySQL_HOME,输入MySQL的安装目录, 然后再把;%MYSQL_HOME%\bin插入到Path的最后面: 第四步:以管理员的身份运行命令行,

2018.11.13 Hibernate 中数据库查询中的Criteria查询实例

Criteria是面向对象的无语句查询 Demo.java package com.legend.b_criteria; import java.util.List; import org.hibernate.Criteria; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.criterion.Order; import org.hibernate.criterion.Pr

oracle 不走索引的几种情况

不走索引的其它原因:   1.建立组合索引,但查询谓词并未使用组合索引的第一列,此处有一个INDEX SKIP SCAN概念.   2.在包含有null值的table列上建立索引,当时使用select count(*) from table时不会使用索引.   3.在索引列上使用函数时不会使用索引,如果一定要使用索引只能建立函数索引.   4.当被索引的列进行隐式的类型转换时不会使用索引.如:select * from t where indexed_column = 5,而indexed_co

Update关联查询不走索引,效率低下

这两天优化一个sql,就是有A,B两个表,要利用b表的字段更新a表对应的字段.形如 Sql代码 update A set A.a=(select B.b from B where A.id=B.id); 原SQL updatepntmall_rptpoint_detail a set a.scrm_rptpnt_processed=( select distinctb.scrm_rptpnt_processed  frompntmall_rptpoint_detail_tmp b where a