# mysql 高级应用 及 pymysql redis
* 复习
* mysql分区
* mysql 导入导出
* mysql 优化
* pymysql
* redis
## 复习
```
更新 update 表名 set 字段名=值 where
删除 delete from 表名 where 条件
truncate table 表名
dcl
grant 权限 on 库.表 to 用户名@'ip地址' identified by '密码' with grant option;
revoke
revoke 权限 on 库.表 from 用户名@'IP地址';
如何减轻数据库的压力
方案:读写分离
解决措施:主从复制
主:写 更新 插入 删除
从:读 查
binlog 日志
表复制 数据复制
视图 view
索引:普通索引 主键索引 唯一索引 全文索引 复合索引
alert table 表名 add index in_name(name,password);#创建了一个复合索引
select * from 表名 where name like '%zelinx%';
rand()
ceiling()
floor()
sum()
count()
avg()
```
## mysql 时间戳 及时间格式化
```
mysql> select unix_timestamp(now());
+-----------------------+
| unix_timestamp(now()) |
+-----------------------+
| 1536197428 |
+-----------------------+
1 row in set (0.00 sec)
mysql> select from_unixtime(1536197428);
+---------------------------+
| from_unixtime(1536197428) |
+---------------------------+
| 2018-09-06 09:30:28 |
+---------------------------+
1 row in set (0.00 sec)
```
## 使用 delete from 表名 后 自增的id 如何修复
```
1.truncate table 表名
2.如果使用了 delete from 表名 接下来 alter table 表名 auto_increment=1; 恢复自增 即可
```
## mysql 分区
```
qq 100亿 条数据
分表 将100亿条数据分成100张表 每张表 1亿条数据
qq_01
qq_100
10101
12345
10000
12334566
122222267
4334343434
ad1234566 字母加数字 分成36张表 截取第一位
123adf
eewrewr78
1.除以100取余
2.截取前几位
3.转成hash值 然后截取前几位
分表
查找数据 :
1.判断位于哪张表中
2.然后查找
分区呢
1.用户还是当成一张表来操作
2.物理形态上分成了5个区
```
## mysql 数据存储方式
```
mysql 数据 以文件的形式存储在服务器上
以 Ubuntu apt-get 安装 mysql 为例子
数据文件存放在 /var/lib/mysql
不同的引擎 存放形式不一样
myisam 引擎的数据表 存储形式 :
1. .frm 数据表的表结构
2. .myi 索引文件
3. .myd 数据文件
innodb 引擎的存储形式
表名.frm 数据表结构文件
表名.ibd 索引文件 和数据文件 共享一个表空间
创建表的时候 进行分区 根据 id 字段进行分区 分成5个 hash分区
mysql> create table t8(id int)engine=myisam default charset=utf8 partition by hash(id) partitions 5;
Query OK, 0 rows affected, 1 warning (0.13 sec)
mysql> create index in_id on t8(id); #另外一种创建索引的方式 这个不能创建 主键索引 其它都可以
Query OK, 0 rows affected, 1 warning (0.10 sec)
Records: 0 Duplicates: 0 Warnings: 1
mysql> insert into t8 values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
Query OK, 10 rows affected, 1 warning (0.01 sec)
Records: 10 Duplicates: 0 Warnings: 1
cd /var/lib/mysql/python1806
watch -d -n 1 ls -lh
mysql> insert into t8 select * from t8; #倍增原理
```
```
什么情况下添加索引?
where 条件后的字段
group by 字段名
order by 字段名
经常使用条件查询 上面 where group by order by 后面的字段 要创建索引
什么情况下 索引失效 ?
1. 使用 模糊查询 比如where name like ‘%haha%’;
2. where name like “ haha%” 只要保证左边没有 % 也可以让索引生效
3. 最左原则 比如 我们给 a b c d 四个字段创建了索引
where a=1 and b=1 and c=1 and d=1; 索引生效
也就是 说 只要 where条件中 有 a 索引就生效 没有a 索引就失效
1. or 条件 or前面字段 创建了 索引 or 后面字段也创建了索引 索引容易失效
```
## mysql 导入导出
```
/usr/bin/mysqldump -u root -p test > /tmp/test.sql #导出
/usr/bin/mysql -u root -p test < /tmp/money.sql #导入
cronteb -e
0 3 * * * /usr/bin/mysqldump -u root -p test > /tmp/test.sql
service cron restart
```
## mysql 只 备份 数据 导入数据
```
先登录到 mysql
mysql -u root -p
mysql> select * from money into outfile "/tmp/money.txt";
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
遇到这种情况
mysql> show variables like "%secure%";
+--------------------------+-----------------------+
| Variable_name | Value |
+--------------------------+-----------------------+
| require_secure_transport | OFF |
| secure_auth | ON |
| secure_file_priv | /var/lib/mysql-files/ | 官方默认允许 从这个目录/var/lib/mysql-files/导入导出
+--------------------------+-----------------------+
1· sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
2. 粘贴一行 secure_file_priv = /tmp #允许将文件导出到 tmp目录下面
3.sudo service mysql restart
root@qulinx-virtual-machine:/tmp# cat money.txt
1 泽林兄 3555524.75 辽宁 19 0
2 秋林兄 1999993.62 黑龙江 18 0
13 金星 123445.56 沈阳 40 1
4 刘强东 4000.00 江苏 40 1
5 抹茶妹妹 77777.66 浙江 30 1
6 范冰冰 1944432.75 山东 40 1
7 李晨 10666658.00 北京 30 0
8 魏缨络 233313.91 上海 29 1
9 薛之谦 3999965.25 上海 30 0
12 鹿晗 1223333.25 江苏 19 0
11 彭麻麻 99999.16 山东 50 1
load data infile "/tmp/money.txt" into table money(也可以指定字段);
```
## 安装pymysql
```
第一种安装方式: pip install pymysql;
第二种安装方式: sudo apt-get install git;
https://github.com/PyMySQL/PyMySQL 打开
然后 git clone https://github.com/PyMySQL/PyMySQL.git
cd PyMySQL/
python setup.py install
```
## mysql事务
```
只有innodb 引擎才支持事务
myisam 和 其它引擎是不支持事务的
1.首先 关闭自动提交
set autocommit=0
delete from 表名;
rollback;
将表改为 innodb 引擎:
alter table 表名 engine=innodb;
```
### 连接数据库
```python
import pymysql # 引入 pymysql对象
'''
连接数据库
参数1:数据库的ip地址
参数2:用户名
参数3:密码
参数4:连接的数据库名称
'''
db = pymysql.connect("127.0.0.1","root","123456","python1806")
#创建一个对象 cursor
cursor = db.cursor()
#准备sql语句
sql = "show tables"
#执行sql语句
cursor.execute(sql)
#获取返回的信息
#data=cursor.fetchone()
data=cursor.fetchall()
print(data)
cursor.close()
db.close()
```
### 创建数据表
```python
import pymysql
db = pymysql.connect("localhost","root","123456","python1806")
cursor = db.cursor()
#检测表是否存在 存在先删除
sql1 = "drop table if exists haha"
cursor.execute(sql1)
sql2= "create table haha(id int(11) unsigned not null primary key auto_increment,username varchar(64) not null default 'shuaige')engine=myisam default charset=utf8"
cursor.execute(sql2)
cursor.close()
db.close()
```
### 插入数据
```python
import pymysql # 引入 pymysql对象
'''
连接数据库
参数1:数据库的ip地址
参数2:用户名
参数3:密码
参数4:连接的数据库名称
'''
db = pymysql.connect("127.0.0.1","root","123456","python1806")
#创建一个对象 cursor
cursor = db.cursor()
#准备sql语句
sql = "insert into haha(username) values('123'),('456'),('789')"
try:
cursor.execute(sql)
db.commit()
except:
db.rollback()
cursor.close()
db.close()
```
### 更新数据
```python
import pymysql # 引入 pymysql对象
'''
连接数据库
参数1:数据库的ip地址
参数2:用户名
参数3:密码
参数4:连接的数据库名称
'''
db = pymysql.connect("127.0.0.1","root","123456","python1806")
#创建一个对象 cursor
cursor = db.cursor()
#准备sql语句
#sql = "insert into haha(username) values('123'),('456'),('789')"
sql = "update haha set username='东方不败' where id=2"
try:
cursor.execute(sql)
db.commit()
except:
db.rollback()
cursor.close()
db.close()
```
### 删除数据
```python
import pymysql # 引入 pymysql对象
'''
连接数据库
参数1:数据库的ip地址
参数2:用户名
参数3:密码
参数4:连接的数据库名称
'''
db = pymysql.connect("127.0.0.1","root","123456","python1806")
#创建一个对象 cursor
cursor = db.cursor()
#准备sql语句
sql = "delete from haha where id=1"
try:
cursor.execute(sql)
db.commit()
except:
db.rollback()
cursor.close()
db.close()
```
### 查询数据
```python
import pymysql # 引入 pymysql对象
'''
连接数据库
参数1:数据库的ip地址
参数2:用户名
参数3:密码
参数4:连接的数据库名称
'''
db = pymysql.connect("127.0.0.1","root","123456","python1806")
#创建一个对象 cursor
cursor = db.cursor()
#准备sql语句
sql = "select * from haha"
try:
cursor.execute(sql) #执行sql语句
result = cursor.fetchall() #取出所有的结果
for row in result:
print("%d--%s" % (row[0],row[1]))
except:
db.rollback()
cursor.close()
db.close()
```
### mysql三大范式
| id | 姓名 | 性别 | 联系方式 |
| ---- | ---- | ---- | --------------------------- |
| 1 | 张三 | 男 | 13888888888 qq 1010101 山东青岛 |
| id | 姓名 | 性别 | 手机 | qq | 省 | 市 | 县 | 镇 |
| :--- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
| | | | | | | | | |
第一个表格 因为 联系方式 可以继续拆分 所以不满足第一范式
总结:第一范式 原子性 就是说 字段 不能再拆分
第二范式 :
首先满足 第一范式 消除字段之间的部分依赖
| 学号 | 姓名 | 课程号 | 班级 |
| ---- | ---- | ---- | ---- |
| | | | |
| 学号 | 姓名 |
| ---- | ---- |
| | |
| 班级号 | 课程 |
| ---- | ---- |
| | |
| 学号 | 课程号 |
| ---- | ---- |
| | |
第三范式
首先满足第二范式 消除字段之间的 传递依赖
消除传递依赖 就是 每个字段 必须完全依赖于 主键
## redis nosql 也叫非关系型数据库
> 常见的nosql :
>
> redis
>
> mongodb
>
> couchdb
>
> memcached
>
> RabbitMQ
只有key value a=[1,2,3] a[0]
内存级数据库 特点:
1.速度快 读的次数是 110000/次 写 81000次
2.开源免费
3.常用的 5种数据类型
### nosql 应用
- 用来 和 mysql 结合使用 当缓存 提高访问速度 减轻mysql 负担
- 好多产品 都在使用redis 处理 好友关系 秒杀 新浪微博 segmentfault
## 安装 redis
> http://www.redis.cn/
```
wget -c http://download.redis.io/releases/redis-3.2.9.tar.gz
tar -zxvf redis-3.2.9.tar.gz
sudo cp -r redis-3.2.9 /usr/local/redis
cd /usr/local/redis
sudo make install
```
### redis 常用的可执行文件 cd /usr/local/redis/src
| 文件 | 说明 |
| --------------- | -------------------------- |
| redis-server | redis 服务器 别的redis 客户端可以连接 |
| redis-cli | redis 客户端 可以连接别的redis服务器 |
| redis-benchmark | redis 性能测试工具 |
| redis-check-aof | aof 修复工具 |
| redis-check-rdb | rdb 修复工具 |
| redis-sentinel | redis 2.8以后 哨兵服务器 |
- src 存放常用的执行文件
- utils 存放自定义启动脚本 比如 开机启动脚本
- /usr/local/redis redis 配置文件在 这里
### redis 数据持久化机制
- aof
- rdb
## 启动redis
```
redis 默认端口号 6379
redis 单个key的大小能达到512M
cd /usr/local/redis/src
sudo ./redis-server
或者直接 sudo /usr/local/redis/src/redis-server
ctrl+c 退出
以上是前台启动
cd /usr/local/redis
sudo vim redis.conf
第128 行
将daemonize no 改为 yes
sudo /usr/local/redis/src/redis-server /usr/local/redis/redis.conf 启动的时候以配置文件启动
ps -aux | grep redis 查看是否启动
grep --color=auto 像这样的是守护进程 不用管
```
### 连接redis
```
在任何目录 都可以使用 redis-cli
或者redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> ping
PONG #返回这个说明 执行成功
exit 退出
```
## 配置redis开机启动
```
cd /usr/local/redis/utils
sudo cp redis_init_script redis_init_script_6379
vim redis_init_script_6379 相当于自己写了一个脚本 通过执行redis 的执行文件 达到启动的目的
sudo vim redis_init_script_6379
REDISPORT=6379 #指定端口号
EXEC=/usr/local/redis/src/redis-server #redis 服务器脚本所在的路径
CLIEXEC=/usr/local/redis/src/redis-cli #redis 客户端所在的路径
PIDFILE=/var/run/redis_${REDISPORT}.pid #指定 redis 进程文件存放目录
CONF="/usr/local/redis/redis_${REDISPORT}.conf" #redis 以哪一个配置文件启动
sudo /usr/local/redis/utils/redis_init_script_6379 start 接下来就可以以这种方式启动
sudo /usr/local/redis/utils/redis_init_script_6379 stop|restart
如果上面提示
redis_6379.pid 已经存在
cd /var/run
sudo rm -rf redis_6379.pid
/usr/local/redis/src/redis-server /usr/local/redis/redis.conf 可以不用这种方式启动了
接下来 加入到开机启动
sudo vim /etc/rc.local
然后最后一行 写入 sudo /usr/local/redis/utils/redis_init_script_6379 start
```
## redis 5个数据类型 常用的这五种 不止这五种
- string
- hash
- list
- set
- zset
### string
> redis 最基本的数据类型 key value key 最大支持512M 二进制 安全性高 可以存储任何数据 图像 音频 视频 数字等
#### 设置 就好比mysql中的 insert set mset
```
set key value
127.0.0.1:6379> set name kangbazi
OK
setex key 时间(秒为单位) value
mset key value key value
```
#### 获取 好比mysql中的 select get mget
```
get key 获取指定 key的值
127.0.0.1:6379> get name
"zelinx"
127.0.0.1:6379> get name
(nil) #value值为空的意思
mget key1 key2 #批量获取指定key中的内容
127.0.0.1:6379> mget python python1
1) "1806"
2) "1807"
```
#### 运算 参与运算的value值必须是int 整型 incr decr incrby decrby incrbyfloat
```
incr key #让制定key的值 自增1
decr key #自减1
incrby key 制定数目
127.0.0.1:6379> decr num #当前值 99
(integer) 99
127.0.0.1:6379> incrby num 1000 #当前值增加 指定值1000 最后结果 1099
(integer) 1099
127.0.0.1:6379> decrby num 500 #自减指定的值
(integer) 599
127.0.0.1:6379> incrbyfloat num 100.123 #自增指定的值为 float 类型
"699.123"
```
#### 追加内容 append
```
append key value #往指定的key中追加内容
127.0.0.1:6379> set names hello
OK #代表存入成功
127.0.0.1:6379> APPEND names world
(integer) 10
127.0.0.1:6379> get names
"helloworld"
```
#### 获取指定key的value值得长度
```
strlen key
```
#### 关于key的操作
```
127.0.0.1:6379> exists kangbazi #exists key 1代表存在 0代表 不存在
(integer) 1
type key #查看key 对应的Value的数据类型 redis常用的五种数据类型
127.0.0.1:6379> type kangbazi
string
127.0.0.1:6379> del kangbazi #del key 删除key
(integer) 1 #1 代表删除成功
expire key 时间 秒为单位 #设置key的过期时间
expire key -1 表示永不过期
ttl key 查看key在内存中的剩余时间
127.0.0.1:6379> expire names 20
(integer) 1
127.0.0.1:6379> ttl names
(integer) 11
127.0.0.1:6379> get names
(nil) 表示过期了
```
### hash 一般用来存储对象 redis 做缓存 用的就是 hash类型 一般 一张数据表 是 一个hash
```
var box = {
name:'kangbazi',
run:function(){
}
}
```
#### 设置 hset
```
hset key 字段名 字段值 #hset person name zelinx
127.0.0.1:6379> hmset user name zhangsan age 18 sex 0 height 181cm weight 100kg 设置多个
OK
```
#### 获取
```
127.0.0.1:6379> hget key 字段名
"zelinx" 值字段值
127.0.0.1:6379> hmget user name age sex height weight 获取多个属性的值
1) "zhangsan"
2) "18"
3) "0"
4) "181cm"
5) "100kg"
获取多个属性和值
127.0.0.1:6379> hgetall user
1) "name"
2) "zhangsan"
3) "age"
4) "18"
5) "sex"
6) "0"
7) "height"
8) "181cm"
9) "weight"
10) "100kg"
获取多个属性
127.0.0.1:6379> hkeys user
1) "name"
2) "age"
3) "sex"
4) "height"
5) "weight"
获取多个 value值
127.0.0.1:6379> hvals user
1) "zhangsan"
2) "18"
3) "0"
4) "181cm"
5) "100kg"
获取数据 个数
127.0.0.1:6379> hlen user
(integer) 5
```
#### 判断 属性是否存在
```
hexists key 字段名 1 存在 0 不存在
127.0.0.1:6379> hexists user name
(integer) 1
127.0.0.1:6379> hexists user sex
(integer) 1
127.0.0.1:6379> hexists user talk
```
#### 删除属性和值
```
hdel key 字段名
127.0.0.1:6379> hdel user name
(integer) 1
127.0.0.1:6379> hkeys user
1) "age"
2) "sex"
3) "height"
4) "weight"
```
#### 查看 属性值得长度 也就是查看key 对应的值得长度
```
127.0.0.1:6379> hstrlen user height
(integer) 5
```
### list
### set
### zset