MySQL数据库4Python操作mysql、索引、慢查询日志

一、Python 操作 mysql

pymysql是通过python操作mysql的模块,需要先安装,方法:pip install pymysql

1.1python 操作 mysql

操作步骤:

1.配置连接数据库的参数

host配置的是IP地址,若果是本机则用localhost,user配置用户权限,之后配置账户和密码,这里的账户密码指登录数据库的账户和密码,database配置需要操作的数据库,之后是配置要链接的数据库的编码。

2.设置默认返回的数据类型

3.发送SQL指令

4.获取返回的数据

import pymysql


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

#cursor = conn.cursor() 默认返回的是元组类型
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
#默认返回字典类型
sql = "select * from userinfo"
cursor.execute(sql)

res1 = cursor.fetchone()#取出一条数据,返回的是字典
print(res1)

res = cursor.fetchall()#取出所有的数据,返回的是列表套字典
print(res)

cursor.close()
conn.close()

{'id': 1, 'name': 'xiaozhu', 'depart_id': 1}
[{'id': 2, 'name': 'xiaoyu', 'depart_id': 1}, {'id': 3, 'name': 'laohe', 'depart_id': 2}, {'id': 4, 'name': 'longge', 'depart_id': 2}, {'id': 5, 'name': 'ludi', 'depart_id': 3}, {'id': 6, 'name': 'xiaoguo', 'depart_id': 4}]

通过例子可以看出数据的读出是一条一条读出的。

1.2查询数据

Python查询Mysql使用 fetchone() 方法获取单条数据,使用

  • fetchall():方法获取多条数据。
  • fetchone(): 该方法获取下一个查询结果集。结果集是一个对象
  • fetchall(): 接收全部的返回结果行.
  • rowcount: 这是一个只读属性,并返回执行execute()方法后影响的行数。
import pymysql


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

#cursor = conn.cursor() 默认返回的是元组类型
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
#默认返回字典类型
sql = "select * from userinfo"
cursor.execute(sql)

res1 = cursor.fetchone()#取出一条数据,返回的是字典
print(res1)

res = cursor.fetchall()#取出所有的数据,返回的是列表套字典
print(res)

res2 = cursor.rowcount#返回的是int型,不能加括号
print(res2)

conn.commit()#对数据的增删改一定要提交,否则更改不成功,而且主键id还会增加,pycharm还不会报错,很坑
cursor.close()
conn.close()

1.3增加(添加、更新)数据

使用到的方法:

cursor.execute()增加一条数据

cursor.executemany()增加多条数据

conn.commit()提交发送的SQL语句

对数据的增删改一定要提交,否则更改不成功,而且主键id还会增加,pycharm还不会报错,很坑

print(cursor.lastrowid)获取最后一行的ID值,只是将原来的最后一行id加一,如果一次插入多行,并不能正确显示主键最后一行的id

例子1插入一条数据

import pymysql


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

#cursor = conn.cursor() 默认返回的是元组类型
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
#默认返回字典类型
sql = "insert into user (name,password) values (%s,%s)"
cursor.execute(sql,('abc','deg'))#括号内填写需要增加的数据,此方式为增加一条数据
print(cursor.lastrowid)#获取最后一行的ID值
conn.commit()#对数据的增删改一定要提交,否则更改不成功,而且主键id还会增加,pycharm还不会报错,很坑
cursor.close()
conn.close()
mysql> select * from user;
+----+----------+----------+
| id | name     | password |
+----+----------+----------+
|  2 | xiaoming | 1563sdi  |
|  3 | abc      | deg      |
|  5 | abc      | deg      |
+----+----------+----------+
3 rows in set (0.00 sec)

例子二插入多条数据

import pymysql

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

#cursor = conn.cursor() 默认返回的是元组类型
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
#默认返回字典类型
data = [('xiaozhu1','145656'),('xiaohzhu2','14965'),('xiaozhu3','61500')]
sql = "insert into user (name,password) values (%s,%s)"
# cursor.execute(sql,('abc','deg'))#括号内填写需要增加的数据


cursor.executemany(sql,data)
print(cursor.lastrowid)#获取最后一行的ID值,只是将原来的最后一行id加一,
# 如果一次插入多行,并不能正确显示主键最后一行的id
conn.commit()#对数据的增删改一定要提交,否则更改不成功,而且主键id还会增加,pycharm还不会报错,很坑
cursor.close()
conn.close()

1.4修改数据

修改数据、增加数据、删除数据其实就是将相应的SQL语句和要修改的对象发送给数据库,然后数据库按照相应的语句进行执行。

import pymysql

conn = pymysql.connect(host='localhost',user='root',
                       password='123zgh',database='test2',
                       charset='utf8')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

sql = "update user set name=%s where id=%s"

cursor.execute(sql,('xiaoyu',2))
conn.commit()
cursor.close()
conn.close()

1.5删除数据

sql = "delete from user where id=%s"

import pymysql

conn = pymysql.connect(host='localhost',user='root',
                       password='123zgh',database='test2',
                       charset='utf8')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

#sql = "update user set name=%s where id=%s"
sql = "delete from user where id=%s"

cursor.execute(sql,(1,))#这里的数据元组里面只有一个元素时不加逗号也可以正常删除,但是最好加上
conn.commit()
cursor.close()
conn.close()

1.6SQL注入问题

1.6.1问题的引入

当我们的登录程序这样写的时候,我们输入用户名:xxx ' or 1=1 #就可以将发送到mysql的指令改变以至于不用用户名和密码也能够获取用户的数据,如输入以后成了select * from user where name='xiaozhu' or 1=1 #' and password='156'则后面的密码部分被注释,where条件也发生了改变or后面的条件始终成立。

import pymysql

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

conn = pymysql.connect(host='localhost',user='root',password='123zgh',
                       database='test2',
                       charset='utf8')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

sql = "select * from user where name='%s' and password='%s'" % (user,pwd)
print(sql)

cursor.execute(sql)
# print(sql)
res = cursor.fetchall()
print(res)
cursor.close()
conn.close()
if res:
    print('登录成功')

else:
    print('登录失败')

1.6.2解决方法

我们在写登录程序时可以使用pymysql提供的方法,或者自己写程序判断用户输入的字符是否有问题。

sql = "select * from user where name=%s and password=%s"

cursor.execute(sql,(user,pwd))

import pymysql

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

conn = pymysql.connect(host='localhost',user='root',password='123zgh',
                       database='test2',
                       charset='utf8')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

sql = "select * from user where name=%s and password=%s" 

cursor.execute(sql,(user,pwd))
# print(sql)
res = cursor.fetchall()
print(res)
cursor.close()
conn.close()
if res:
    print('登录成功')

else:
    print('登录失败')

二、索引

mysql的索引作用和字典的索引,图书馆的图书索引的作用都是一样的,目的都是为了提高查找的速度。

2.1索引的本质

数据库的索引本质是一个特殊的文件,可以提高数据的查找速度。

2.2索引的底层原理

底层原理是B+树(涉及的数据结构与算法知识较多,以后有机会再做介绍)

2.3索引的分类

2.3.1主键索引

依据primary key进行查找数据,特点:提高查找效率,且主键的记录数据不重复,不为空

2.3.2唯一索引

添加方式:某一列的字段名的数据类型后面加unique(字段名)

特点:提高查找效率,且唯一索引记录数据不重复,不为空

2.3.3联合唯一索引

添加方式:unique(字段名1,字段名2......)

特点:提高查找效率,且组合在一起的字段记录数据不重复(单列数据可以重复,组合在一起不能重复),不为空

2.3.4普通索引

index(字段名)

特点:没有上述主键唯一索引对数据的要求

2.3.5联合索引

index(字段1,字段2……)

特点:没有上述主键唯一索引对数据的要求

2.4索引的创建

2.4.1主键索引的创建与删除

2.4.1.1新增主键索引

方式1
create table xxx(
id int auto_increment primary key
);
方式2
create table xxx(
id int auto_increment, primary key(id)
);
方式3
alter table xxx change id id int auto_increment primary key;
方式4
alter table yyy add primary key (id);

2.4.1.2删除主键索引

如果主键是自增id,不能直接使用下面的方法删除,需要先将其修改为非自增id,然后再用下面的方法删除(这种情况在实际应用中几乎不会出现)。

alter table yyy drop primary key;

2.4.2唯一索引的创建与删除

2.4.2.1创建唯一索引

方式1
create table XXX(
    id int auto_increment primary key,
	name varchar(32) not null default '',
	unique u_name (name) )
    #u_name是给唯一索引起的名字,方便以后删除索引或查找问题
方式2
create unique index 索引名 on 表名 (字段名);
方式3
alter table 表名 add unique index 索引名(字段名)

2.4.2.2删除唯一索引

alter table 表名 drop index 索引名;

2.4.3普通索引的创建与删除

2.4.3.1普通索引的创建

方式1
create table 表名(
    id int auto_increment primary key,
    name varchar(32) not null default '',
    index 普通索引名(字段名)
)
方式2
create index 索引名 on 表名(字段名);
方式3
alter table 表名 add index 索引名(字段名);

2.4.3.2普通索引的删除

alter table 表名 drop index 索引名;

2.5索引的优缺点

优点:加快了查询速度

缺点:占用了大量的磁盘空间*.ibd是存储数据和索引的文件,可通过查看这个文件的大小对比创建索引前和创建索引后的差别。

2.6不会命中索引的情况

2.6.1不会命中索引的情况

不会命中索引指:创建的索引么有用上,没有达到快速查找的目的。

情况1

在SQL语句中使用四则运算,会降低SQL的查询效率。

情况2

在SQL语句中使用函数。如

select * from user where reverse(email) = 'guanghao';
#reverse的功能是反转'guanghao'然后在email里面查找

情况3

类型不一致:如果列是字符串类型,传入的条件必须先加引号,不然找不着。

情况4

排序条件为索引,则select字段也必须是索引字段,否则无法命中。

如使用order by时

select name from user order by email desc;

上面的SQL语句如果email是索引,则select email可以通过索引快速查找,如果select 的不是索引那一列,则不会触发索引,查找速度依然很慢。

例外情况:如果对主键排序,查找其他列条件,速度也很快。

如select * from 表名 order by id desc;

情况5

count(1)、count(列)、count(*)查找速度没太大差别

情况6

组合索引遵循最左前缀原则

当创建联合索引时如name,email均创建了索引,则可以命中索引的查找方式有:

方式1
select * from user where name='guanghao' and email='guanghao@qq.com';
方式2
select * from user where name='guanghao';

如果where 后面的条件是email则无法命中索引。

如果联合索引的列不止两列则要从左向右按顺序排列查找才可以命中索引,如果中间跳过了某列只要最左边列存在就能够命中索引。如下例

index(a,b,c,d)
where a=1 and b=2 and c=3 and d=4 #命中索引
where a=1 and c=3 and d=4 #命中索引

2.6.2查看索引是否命中的方法

explain select * from 表名 where 查询的条件G;

如:
mysql> explain select password from user where id=6G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: user
         type: const
possible_keys: PRIMARY 可能用到的索引
          key: PRIMARY 确实用到的索引
      key_len: 4       索引长度
          ref: const   
         rows: 1       扫描的长度(这里可以确定是否使用了索引)
        Extra: NULL    是否使用了索引
1 row in set (0.00 sec)

2.6.3索引覆盖

索引覆盖就是按照索引去查数据。

2.7慢查询日志

2.7.1查看慢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   慢日志查询是默认关闭状态                      |
| slow_query_log_file       | E:mysqlmysql-5.6.46-winx64dataGH-PC-slow.log |记录慢日志的位置,
+---------------------------+---------------------------------------------------+可配置
5 rows in set (0.03 sec)

mysql> show variables like '%long%';
+--------------------------------------------------------+-----------+
| Variable_name                                          | Value     |
+--------------------------------------------------------+-----------+
| long_query_time                                        | 10.000000 |
默认当查找时间大于10秒会记录为慢SQL,我们需要对其进行配置修改其记录为慢SQL的时间。

2.7.2配置慢SQL的变量

set global 变量名 = 值
				 
set global slow_query_log = on;慢日志查询配置为on
				
set global slow_query_log_file="D:/mysql-5.6.46/data/myslow.log";配置慢日志存储路径(路径不能有空格,否则会配置不成功)
				
set global long_query_time=1;配置记录为慢日志的捕捉时间
原文地址:https://www.cnblogs.com/ghylpb/p/11774105.html