Tiny_Lu
不忘初心

Day 36 SQL基础(四)

pymysql

pymysql操作mysql

import pymysql


# 连接数据库参数
conn = pymysql.connect(host='localhost', user='root', password='', datebase='test', charset='utf8')
# 默认返回的是元组类型
# cursor = conn.cursor()

# 返回的是字典类型
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

sql = 'select * from class'

# 执行SQL语句
cursor.execute(sql)

# res = cursor.fetchall()  # 取出所有的数据,返回的是列表套字典
# res = cursor.fetchone()  # 取出一条数据,返回的是字典类型
res = cursor.fetchmany(12)  # 设置获取多少条数据,返回的是列表套字典
print(res)


cursor.close()
conn.close()

pymysql的sql注入

import pymysql

user = input('输入用户名:').strip()
pwd = input('输入密码:').strip()

# 接下来对用户输入的值进行检验

# 连接数据库的参数
conn = pymysql.connect(host='localhost', user='root', password='123', database='test', charset='utf8')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

sql = 'select * from student where sid = %s and sname = %s'

# 在execute中以元组形式传入可以有效避免SQL注入带来的安全问题
cursor.execute(sql, (pwd, user))
res = cursor.fetchall()
print(res)


cursor.close()
conn.close()

if res:
    print('登录成功')
else:
    print('登录失败')

pymysql增加数据

import pymysql

class_id = input('输入id:').strip()
class_name = input('输入班级:').strip()

# 接下来对用户输入的值进行检验

# 连接数据库的参数
conn = pymysql.connect(host='localhost', user='root', password='123', database='test', charset='utf8')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

sql = 'insert into class values (%s, %s)'

cursor.execute(sql, (class_id, class_name))
res = cursor.fetchall()

# 对数据库的增删改都需要加上commit
conn.commit()


cursor.close()
conn.close()

pymysql修改数据

import pymysql

class_id = input('输入id:').strip()
class_name = input('输入班级:').strip()

# 接下来对用户输入的值进行检验

# 连接数据库的参数
conn = pymysql.connect(host='localhost', user='root', password='123', database='test', charset='utf8')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

sql = 'update class set caption=%s where cid=%s'

cursor.execute(sql, (class_name, class_id))
res = cursor.fetchall()

conn.commit()

pymysql删除数据

import pymysql

class_id = input('输入id:').strip()
class_name = input('输入班级:').strip()

# 接下来对用户输入的值进行检验

# 连接数据库的参数
conn = pymysql.connect(host='localhost', user='root', password='123', database='test', charset='utf8')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

sql = 'delete from class where cid = %s'

cursor.execute(sql, (class_id))
res = cursor.fetchall()

conn.commit()

索引

索引的原理

索引的目的在于提高查询效率,与我们查阅图书所用的目录是一个道理:先定位到章,然后定位到该章下的一个小节,然后找到页数。相似的例子还有:查字典,查火车车次,飞机航班等

本质都是:通过不断地缩小想要获取数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是说,有了这种索引机制,我们可以总是用同一种查找方式来锁定数据。

数据库也是一样,但显然要复杂的多,因为不仅面临着等值查询,还有范围查询(>、<、between、in)、模糊查询(like)、并集查询(or)等等。数据库应该选择怎么样的方式来应对所有的问题呢?我们回想字典的例子,能不能把数据分成段,然后分段查询呢?最简单的如果1000条数据,1到100分成第一段,101到200分成第二段,201到300分成第三段......这样查第250条数据,只要找第三段就可以了,一下子去除了90%的无效数据。但如果是1千万的记录呢,分成几段比较好?稍有算法基础的同学会想到搜索树,其平均复杂度是lgN,具有不错的查询性能。但这里我们忽略了一个关键的问题,复杂度模型是基于每次相同的操作成本来考虑的。而数据库实现比较复杂,一方面数据是保存在磁盘上的,另外一方面为了提高性能,每次又可以把部分数据读入内存来计算,因为我们知道访问磁盘的成本大概是访问内存的十万倍左右,所以简单的搜索树难以满足复杂的应用场景。

索引的种类

主键索引:加速查找 + 不能重复 + 不能为空 primary key

唯一索引:加速查找 + 不能重复

​ 联合唯一索引: unique(name, email)

普通索引:加速查找 index(name)

​ 联合索引: index(name, email)

索引的创建

主键索引

新增主键索引:

create table xxx(
id int auto_increment primary key,
name varchar(32) not null default '',
email vaechar(32) not null default ''
)charset utf8;
alter table xxx add primary key (id);

删除主键索引:

alter table xxx drop primary key;

唯一索引

新增唯一索引:

create table xxx(
id int auto_increment primary key,
name varchar(32) not null default '',
unique index u_name (name)
)charset utf8
alter table xxx add unique index u_name(name);
create unique index u_name on xxx (name);

删除唯一索引:

alter table xxx drop index u_name;

普通索引

新增普通索引:

create table xxx(
id int auto_increment primary key,
name varchar(32) not null default '',
index ix_name (name)
)charset utf8
create index ix_name on xxx (name);
alter table xxx add index ix_name (name);

删除普通索引:

alter table xxx drop index ix_name;

索引的优缺点

优点:

索引可以明显的加快查询速度

缺点:

加上索引之后,会占用打了的磁盘空间

不会命中索引的情况

  1. 在SQL语句中进行四则运算,会降低查询效率
  2. 在where条件中使用函数
  3. 类型不一致.如果列是字符串类型.传入条件是必须引号引起来
  4. 排序条件为索引,则select字段必须也是索引字段,否则无法命中.但是特殊的是,对主键进行排序时,查询效率依旧很高
  5. 联合索引最左前缀才会命中索引

性能分析值explain

explain语法:

explain select ... from ...[where ...]

输出:

+--+-----------+-----+----+-------------+---+-------+---+----+-----+
|id|select_type|table|type|possible_keys|key|key_len|ref|rows|Extra|
+--+-----------+-----+----+-------------+---+-------+---+----+-----+
  1. id: 这是select的查询序列号
  2. select_type: select_type就是select的类型,可以有以下几种:
  • SIMPLE: 简单SELECT(不使用UNION或者子查询等)
  • PRIMARY: 最外面的SELECT
  • UNION: union中的第二个或后面的SELECT语句
  • DEPENDENT UNION:UNION中的第二个或后面的SELECT语句,取决于外面的查询
  • UNION RESULT:UNION的结果
  • SUBQUERY:子查询中的第一个SELECT
  • DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询
  • DERIVED:导出表的SELECT(FROM子句的子查询)
  1. table: 显示这一行的数据是关于哪张表的
  2. type: 这列最重要,显示了连接使用了哪种类别,有无使用索引,是使用Explain命令分析性能瓶颈的关键项之一
结果值从好到坏依次是:

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

一般来说,得保证查询至少达到range级别,最好能达到ref,否则就可能会出现性能问题。
  1. possible_keys: 列指出MySQL能使用哪个索引在该表中找到行
  2. key: 显示MySQL实际决定使用的键(索引).如果没有选择索引,键是NULL
  3. key_len: 显示MySQL决定使用的键长度.如果键是NULL,则长度为NULL.使用的索引的长度.在不损失精确性的情况下,长度越短越好
  4. ref: 显示使用哪个列或常数与key一起从表中选择行.
  5. rows: 显示MySQL认为它执行查询时必须检查的行数.
  6. Extra: 包含MySQL解决查询的详细信息,也是关键参考项之一.
Distinct
一旦MYSQL找到了与行相联合匹配的行,就不再搜索了

Not exists
MYSQL 优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,

就不再搜索了

Range checked for each

Record(index map:#)
没有找到理想的索引,因此对于从前面表中来的每一 个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一

Using filesort
看 到这个的时候,查询就需要优化了。MYSQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来 排序全部行

Using index
列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表 的全部的请求列都是同一个索引的部分的时候

Using temporary
看到这个的时候,查询需要优化了。这 里,MYSQL需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上

Using where
使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index, 这就会发生,或者是查询有问题

慢查询日志

查看慢SQL的相关变量:

mysql> show variables like '%slow%';
+---------------------------+-----------------------------------------------+
| Variable_name             | Value                                         |
+---------------------------+-----------------------------------------------+
| log_slow_admin_statements | OFF                                           |
| log_slow_slave_statements | OFF                                           |
| slow_launch_time          | 2                                             |
| slow_query_log            | OFF   ### 默认关闭慢SQl查询日志, on              |
| slow_query_log_file       | D:\mysql-5.7.28\data\DESKTOP-910UNQE-slow.log | ## 慢SQL记录的位置
+---------------------------+-----------------------------------------------+
5 rows in set, 1 warning (0.08 sec)
mysql> show variables like '%long%';
+----------------------------------------------------------+-----------+
| Variable_name                                            | Value     |
+----------------------------------------------------------+-----------+
| long_query_time                                          | 10.000000 |

配置慢SQL的变量:

### set global 变量名 = 值 ###
				 
set global slow_query_log = on;
				
set global slow_query_log_file="D:/mysql-5.7.28/data/myslow.log";
				
set global long_query_time=1;
posted @ 2019-10-31 21:10  二二二二白、  阅读(127)  评论(0编辑  收藏  举报