pymysql ,主键, 索引
一、pymysql
模块的使用
1. 安装pymysql
pymysql
属于第三方库,要先下载安装。
2. 连接MySQL
- 连接并操作MySQL的步骤
创建连接
创建游标
创建SQL语句
执行SQL语句
接收查询结果(当对数据进行查询时,才会有此步骤)
fetchall()/fetchone()/fetchmany(size)
查询结果是列表套字典的格式。若返回的是空,根据创建游标时,让返回的数据是列表套字典形式还是默认的元组形式。对应为[]或()
提交(当对数据进行增、删、修改时,才会有此步骤)即
commit()
关闭游标
关闭连接
- 查询实例:
import pymysql
conn = pymysql.connect(host='localhost',user='root',password='123qwe',database='test',charset='utf8')
# cursor = conn.cursor() ### 默认返回的值是元组类型*************
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) ### 返回的值是字典类型 (*********)
sql = "select * from userinfo"
cursor.execute(sql)
# res = cursor.fetchall() ###取出所有的数据 返回的是列表套字典
# res = cursor.fetchone() ###取出一条数据 返回的是字典类型
res = cursor.fetchmany(12) ### 指定获取多少条数据 返回的是列表套字典,若超过最大数据行数,则只会返回全部的数据。
cursor.close()
conn.close()
- 插入实例:
print(cursor.lastrowid) ### 获取最后一行的ID值
在插入时使用才有效果,在其他sql语句中,返回的是None
import pymysql
### 连接数据库的参数
conn = pymysql.connect(host='localhost',user='root',password='123qwe',database='test',charset='utf8')
# cursor = conn.cursor() ### 默认返回的值是元组类型
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) ### 返回的值是字典类型 (*********)
sql = "insert into user (name, password) values (%s, %s)"
cursor.execute(sql, ('dshadhsa', 'dbsjabdjsa')) ### 新增一条数据
print(cursor.lastrowid) ### 获取最后一行的ID值
# 一次性插入多条数据***************
# data 必须是列表套元组
# data = [
# ('zekai1', 'qwe'),
# ('zekai2', 'qwe1'),
# ('zekai3', 'qwe2'),
# ('zekai4', 'qwe3'),
# ]
# cursor.executemany(sql, data) ### 新增多条数据
#### 加如下代码
conn.commit()
cursor.close()
conn.close()
3. sql注入问题
产生原因:因为过于相信用户输入的内容,对输入的内容根本没有任何的检验,导致内容中一些关键字符传入,在执行含有这些关键字符的SQL语句时,返回了不正确的结果。
实例:
user_name = zekai ' or 1=1 #
pwd = dsadsa # 我们即将提交的SQL语句
sql = 'select * from user where name = %s and password = %s' % (user_name ,pwd) # 真正提交执行的SQL语句 '#'表示注释的意思
select * from user where name='zekai ' or 1=1 #' and password='dsadsa' # 查询后返回的结果
# 由于判断密码的条件被#注释掉了,所以只会匹配前面的,而前面又有 关键字 or
[{'id': 1, 'name': 'zhangsan', 'password': ''},{'id': 2, 'name': 'zekai', 'password': '123'}]
解决的方法:注意下面的星号中间的内容
对用户输入的内容进行检验之后,再写入SQL语句
利用pymysql的内置方法排查。
以下是第二种方法的实例:
user_name = zekai ' or 1=1 #
pwd = dsadsa # 对用户输入的信息先不直接拼接进sql语句的字符串,对用户输入的信息先用 %s 代替。将用户输入的信息放在一个元组/列表 中,传入execute方法中。 ****************************************************************************************************
# 此时要注意一点:就是pymysql的execute方法会把传入的元组或列表中的元素依次取出来,依次传给sql字符串中的 %s 。所以有多少个元素,就要有多少个%s 。
*************************************************************************************************** sql = "select * from user where name=%s and password=%s" 使用pymysql自带的方法,把要传的值放进去,就会自动校验用户输入内容的敏感字符
cursor.execute(sql, (user_name, pwd)) # 查询后返回的结果,为空
# []
二、索引
1. 什么是索引
- 索引在MySQL中也叫是一种“键”,是存储引擎用于快速找到记录的一种数据结构
2. 索引有什么用
加快查询速度。
mysql中的primary key,unique,联合唯一也都是索引,这些索引除了加速查找以外,还有约束的功能
注意1:虽然索引能加快查询速度,但并不是索引越多越好,当数据过多时,创建索引需要的时间也越多,而且还会占用更多的磁盘空间。 若索引太多,应用程序的性能可能会受到影响。而索引太少,对查询性能又会产生影响,要找到一个平衡点,这对应用程序的性能至关重要 。
注意2:在向一张表中插入数据时,若之前已经对该表的字段建立了索引,则数据库会先把索引删掉,再插入数据,之后再把索引添加回来。
3. 索引的底层原理
- 索引底层的算法使用的是 B+树 。
4. 主键
1、数据库的每张表只能有一个主键,不可能有多个主键。
2、所谓的一张表多个主键,我们称之为联合主键。
注:联合主键就是用多个字段一起作为一张表的主键。
3、主键的作用是保证数据的唯一性和完整性,同时通过主键检索表能够增加检索速度。
5. MySQL中索引的分类
- 普通索引INDEX:加速查找
- 唯一索引:
- 主键索引PRIMARY KEY:加速查找+约束(不为空、不能重复)
- 唯一索引UNIQUE:加速查找+约束(不能重复)
- 联合索引:
- PRIMARY KEY(id,name):联合主键索引
- UNIQUE(id,name):联合唯一索引
- 添加了联合唯一索引的这些字段,我们可以对其任意一个再添加单个的普通索引。如
unique(a,b) , 之后还可以 alter table 表名 add index 字段名1(a) alter table 表名 add index 字段名2(b)
- 对于添加了联合唯一索引的字段,它的唯一性指的是全部字段数据作为一个整体,不能和其他整体相同。如
unique(a,b) a,b是字段名,int类型,我们插入(1,2)之后不能插入(1,2)了,但可以插入 (1.3)或(2,2)等等
- 添加了联合唯一索引的这些字段,我们可以对其任意一个再添加单个的普通索引。如
- INDEX(id,name):联合普通索引
- 添加了联合普通索引的这些字段,我们可以对其任意一个再添加单个的普通索引
6. 索引的创建
(0)创建索引的技巧:
- 在开发程序时,一边开发一边创建, 在需要的地方添加索引
- 对查询频率高的字段创建合适类型的索引
- 尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0
- 注意2:在向一张表中插入数据时,若之前已经对该表的字段建立了索引,则数据库会先把索引删掉,再插入数据,之后再把索引添加回来。所以,我们在向表中录入大量数据时:若是新表,录入数据之后再创建索引;若是已经有索引的表:先把原来的索引删掉,等数据录入完成后,再把索引恢复。通过这样的两种方法这样会大大提高数据库录入大量数据的效率。
其他注意的地方:
- 避免使用select *
- 避免使用count(*)
- 创建表时尽量使用 char 代替 varchar
- 表的字段顺序固定长度的字段优先
- 组合索引代替多个单列索引(由于mysql中每次只能使用一个索引,所以经常使用多个条件查询时更适合使用组合索引)
- 尽量使用短索引
- 使用连接(JOIN)来代替子查询(Sub-Queries),即代替嵌套查询
- 连表时注意条件类型需一致
- 索引散列值(重复少)不适合建索引,例:性别不适合
(1)创建主键索引
创建表时创建主键索引
1.
create table xxx(
id int auto_increment ,
primary key(id) # 创建主键索引
)charset utf8;
2.
create table xxx( id int auto_increment primary key # 创建主键索引
)charset utf8;
创建表后创建主键索引
1.
alter table 表名 change 原字段名 新字段名 字段类型 auto_increment primary key;
2.
alter table 表名 modify 字段名 字段类型 auto_increment primary key;
3.
alter table 表名 add primary key (字段名);
删除主键索引
alter table 表名 drop primary key;
(2)创建唯一索引
创建表时创建唯一索引
create table t2(
id int auto_increment primary key,
name varchar(32) not null default '',
unique u_name (name) # 创建唯一索引
)charset utf8;
创建表后创建唯一索引
1.
CREATE UNIQUE INDEX 索引名 ON 表名 (字段名) ;
2.
alter table 表名 add unique index 索引名 (字段名);删除唯一索引
alter table 表名 drop index 索引名;
(3)创建普通索引
创建表时创建普通索引
create table t3(
id int auto_increment primary key,
name varchar(32) not null default '',
index u_name (name) # 创建普通索引
)charset utf8;
创建表后创建普通索引
1.
CREATE INDEX 索引名 ON 表名 (字段名)
2.
alter table 表名 add index 索引名 (字段名)
删除普通索引
alter table 表名 drop index 索引名;
(4)联合索引的创建
- 联合索引的创建只是在创建其他索引时,字段是多个而已
联合唯一索引:unique 索引名(name, email)
联合索引: index 索引名(name, email)
- 什么时候创建联合索引
根据公司的业务场景, 在最常用的几列上添加索引
select * from user where name='zekai' and email='zekai@qq.com';
如果遇到上述业务情况, 错误的做法:
index ix_name (name),
index ix_email(email)
正确的做法:
index ix_name_email(name, email)
7. 索引未命中情况
- 范围问题,或者说条件不明确,条件中出现这些符号或关键字:>、>=、<、<=、!= 、between...and...、like
a. 不能在SQl语句中,进行四则运算, 会降低SQL的查询效率
b. 使用函数
select * from tb1 where reverse(email) = 'zekai';
c. 类型不一致
如果列是字符串类型,传入条件是必须用引号引起来,否则不会命中索引
select * from tb1 where email = 999;
#排序条件为索引,则select字段必须也是索引字段,否则无法命中
d. order by
select name from s1 order by email desc;
当根据索引排序时候,select查询的字段如果不是索引,则速度仍然很慢
select email from s1 order by email desc;
特别的:如果对主键排序,则还是速度很快:
select * from tb1 order by nid desc;
e. ***********count(1)或count(*)代替count(列)*************
1.执行效率上:
列名为主键,count(列名)和count(1) 和 count(*) 执行效率是一样的:因为 explain 中 type 类型都为 index
列名不为主键,而且列名没有创建索引 但是 其他字段创建了索引:count(1) = count(*) > count(列名) :因为expalin 中的 type 类型 count(1) 和 count(*) 类型都为 index 而 count(列名) 的 type 类型为 all
列名不为主键,但是 列名 创建索引 :count(1) = count(*)= count(列名) :因为 explain 中 type 类型都为 index
如果表多个列并且没有主键,则 count(1) 的执行 = 优于 count(*)
如果表只有一个字段,则 select count(*)和 select count(1) and select count(字段名)执行效率一样。
2. count(1) and count(字段) and count(*)
主要区别是
(1) count(1) 会统计表中的所有的记录数,包含字段为null 的记录。
(2) count(字段) 会统计该字段在表中出现的次数,忽略字段为null 的情况。即不统计字段为null 的记录。
(3) count(*) 会统计表中的所有的记录数,包含字段为null 的记录。
3.执行效果上:
count(*)包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL
count(1)包括了忽略所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL
count(列名)只包括列名那一列,在统计结果的时候,某个字段值为NULL时,不统计
f. 组合索引最左前缀***********************************************
只有包含最左边即首部第一个字段的where条件,才会命中索引,否则不会命中索引。如例子:
index (a,b,c,d)
where a=2 and b=3 and c=4 and d=5 --->命中索引
where a=2 and b=3 and c=4 ——>命中
where a=2 and c=3 and d=4 ----> 命中
where b=2 and c=3 ----->未命中
什么时候会创建联合索引?
根据公司的业务场景, 在最常用的几列上添加索引
select * from user where name='zekai' and email='zekai@qq.com';
如果遇到上述业务情况, 错误的做法:
index ix_name (name),
index ix_email(email)
正确的做法:
index ix_name_email(name, email)
如果组合索引为:
ix_name_email (name,email) ************
where name='zekai' and email='xxxx' -- 命中索引
where name='zekai' -- 命中索引
where email='zekai@qq.com' -- 未命中索引
8. explain
查看SQL语句执行情况
explain 关键字的作用:
mysql> explain select * from user where name='zekai' and email='zekai@qq.com'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
partitions: NULL
type: ref 索引指向 all
possible_keys: ix_name_email 可能用到的索引
key: ix_name_email 确实用到的索引
key_len: 214 索引长度
ref: const,const
rows: 1 扫描的行数
filtered: 100.00
Extra: Using index 使用到了索引
注意:判断是否命中索引最准确的还是要看 rows 这一行的结果。
9. 索引覆盖
select id from user where id=2000;
#where 条件的字段和查询字段相同
10.慢日志管理
步骤:
查看慢日志的变量
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)
配置慢SQL的变量:
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; # 设定最大查询时间
pymysql ,主键, 索引的更多相关文章
- 1226关于count(*)不走主键索引反而走二级索引
转自 http://www.2cto.com/database/201508/433975.html mysqlcount(*)会选哪个索引? 2015-08-19 0个评论 来源:D ...
- 修改mysql表结构,添加一个主键索引自增字段,修改原来的主字段为普通字段
原来有一个字段id,为自增,主键,索引.现在要新增一个字段s_id为自增,主键,索引.同时把原来的主字段改成普通字段,默认值为0. Alter table e_diamond_jhds change ...
- Mysql索引介绍及常见索引(主键索引、唯一索引、普通索引、全文索引、组合索引)的区别
Mysql索引概念:说说Mysql索引,看到一个很少比如:索引就好比一本书的目录,它会让你更快的找到内容,显然目录(索引)并不是越多越好,假如这本书1000页,有500也是目录,它当然效率低,目录是要 ...
- MYSQL的全表扫描,主键索引(聚集索引、第一索引),非主键索引(非聚集索引、第二索引),覆盖索引四种不同查询的分析
文章出处:http://inter12.iteye.com/blog/1430144 MYSQL的全表扫描,主键索引(聚集索引.第一索引),非主键索引(非聚集索引.第二索引),覆盖索引四种不同查询的分 ...
- Mysql主键索引、唯一索引、普通索引、全文索引、组合索引的区别
原文:Mysql主键索引.唯一索引.普通索引.全文索引.组合索引的区别 Mysql索引概念: 说说Mysql索引,看到一个很少比如:索引就好比一本书的目录,它会让你更快的找到内容,显然目录(索引)并不 ...
- 删除指定表的所有索引,包括主键索引,唯一索引和普通索引 ,适用于sql server 2005,
原文:删除指定表的所有索引,包括主键索引,唯一索引和普通索引 ,适用于sql server 2005, --删除指定表中所有索引 --用法:declare @tableName varchar(100 ...
- mysql索引之主键索引
MySQL目前主要有以下几种索引类型:1.普通索引2.唯一索引3.主键索引4.组合索引5.全文索引 二.语句 CREATE TABLE table_name[col_name data type] [ ...
- 唯一索引 && 主键索引
唯一索引唯一索引不允许两行具有相同的索引值. 如果现有数据中存在重复的键值,则大多数数据库都不允许将新创建的唯一索引与表一起保存. 当新数据将使表中的键值重复时,数据库也拒绝接受此数据.例如,如果在 ...
- PostgreSQL主键索引膨胀的重建方法
普通的索引膨胀处理比较简单,主键的索引膨胀也不复杂,只是在新旧索引交替时有一些小处理.本试验在primary key上通过CONCURRENTLY建立第二索引来解决索引膨胀问题,适用9.3.9.4,其 ...
- mysql死锁-非主键索引更新引起的死锁
背景:最近线上经常抛出mysql的一个Deadlock,细细查来,长了知识! 分析:错误日志如下: 21:02:02.563 ERROR dao.CommonDao [pool-15-t ...
随机推荐
- 阶段3 2.Spring_07.银行转账案例_6 测试转账并分析案例中的问题
转账回滚这里把异常打印出来.AccountServiceTest.java 把数据库的金额现在都改成1000块 运行测试方法 这里已经报错了. 刷新数据库内的数据.这样我们事物就控制成功了. 事物控制 ...
- SAS中的聚类分析方法总结
SAS中的聚类分析方法总结 说起聚类分析,相信很多人并不陌生.这篇原创博客我想简单说一下我所理解的聚类分析,欢迎各位高手不吝赐教和拍砖. 按照正常的思路,我大概会说如下几个问题: 1. 什么是 ...
- 原生dapper中新增用户后根据用户id,在用户角色表中添加关联数据,事务处理
var result = 0; var userId = 0; using (var db = _Sql.Connection) using (var tran =db.BeginTransactio ...
- springmvc请求参数获取(自动绑定)的几种方法
1.直接把表单的参数写在Controller相应的方法的形参中,适用于get方式提交,不适用于post方式提交. /** * 1.直接把表单的参数写在Controller相应的方法的形参中 * @pa ...
- poatman接口测试--初试
接到测试任务,对两个商品接口,进行接口测试 测试工具:postman 域名:rap2查找的或询问开发, 接口的参数规则:参考rap2的备注 开发没有添加详细说明的,让开发补充说明规则,及定义的返回状态 ...
- Multi-Object-Edit With Django FormSets
I had to write a multi-object edit table the other day for a Django project and as such I dove into ...
- SpringCloud 和 Dubbo 有哪些区别?
首先,他们都是分布式管理框架. dubbo 是二进制传输,占用带宽会少一点.SpringCloud是http 传输,带宽会多一点,同时使用http协议一般会使用JSON报文,消耗会更大. ...
- 20191209 【归档】Linux就该这么学
学习背景 因为打算学习Redis和Docker,但是发现对Linux的操作已经完全忘记了,所以选择再学一次,但是不会深入的学习,选择了<Linux就该这么学>这本书,学完了感觉还挺好,但是 ...
- 第十四周课程总结&&实验总结
课程总结: 1.Java实现跨平台操作的工具:JDBC. 它的意思是java数据库连接,可以方便的实现多种关系型数据库的统一操作,它由一组用java语句编写的类和接口组成. 2.JDBC驱动分类: J ...
- Linux系统管理和调优(内存、CPU、磁盘IO、网络)
系统管理 Author:Rich七哥 查看 CPU 负载相关工具,找出系统中使用 CPU 最多的进程 查看 Memory 运行状态相关工具,找出系统中使用内存最多的进程 查看 IO 运行状态相关工具, ...