python中的urlencode与urldecode

当url地址含有中文,或者参数有中文的时候,这个算是很正常了,但是把这样的url作为参数传递的时候(最常见的callback),需要把一些中文甚至'/'做一下编码转换。

一、urlencode

urllib库里面有个urlencode函数,可以把key-value这样的键值对转换成我们想要的格式,返回的是a=1&b=2这样的字符串,比如:

>>> from urllib import urlencode 
>>> data = { 
... 'a': 'test', 
... 'name': '魔兽' 
... } 
>>> print urlencode(data) 
a=test&name=%C4%A7%CA%DE

如果只想对一个字符串进行urlencode转换,怎么办?urllib提供另外一个函数:quote()

>>> from urllib import quote 
>>> quote('魔兽') 
'%C4%A7%CA%DE'

二、urldecode

当urlencode之后的字符串传递过来之后,接受完毕就要解码了——urldecode。urllib提供了unquote()这个函数,可没有urldecode()!

>>> from urllib import unquote 
>>> unquote('%C4%A7%CA%DE') '\xc4\xa7\xca\xde' 
>>> print unquote('%C4%A7%CA%DE') 
魔兽

三、讨论

在做urldecode的时候,看unquote()这个函数的输出,是对应中文在gbk下的编码,在对比一下quote()的结果不难发现,所谓的urlencode就是把字符串转车gbk编码,然后把\x替换成%。如果你的终端是utf8编码的,那么要把结果再转成utf8输出,否则就乱码。

可以根据实际情况,自定义或者重写urlencode()、urldecode()等函数。

python爬虫练手

51无聊谢了个爬虫玩

python写这类小东西真的很方便

__author__='LeoKim'
from bs4 import BeautifulSoup
 
import re
import urllib.request, urllib.parse, http.cookiejar
import json
import time
import pymysql

conn=pymysql.connect(host='localhost',user='root',passwd='superhero',db='python_test',port=3306,charset='utf8')
cur=conn.cursor()#获取一个游标

#通过链接获取每页的小区名
def getVillage(url):
	cj = http.cookiejar.CookieJar()
	opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
	opener.addheaders = [('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36'),
	('Cookie', 'select_city=320100; lianjia_uuid=c73af582-9ed7-42ed-9738-bbd4688c67e0; UM_distinctid=15bb9f33ca387c-0ac15874ad5d0d-6a11157a-1fa400-15bb9f33ca4a02; _jzqckmp=1; all-lj=c28812af28ef34a41ba2474a2b5c52c2; _jzqx=1.1493473537.1493544561.2.jzqsr=nj%2Elianjia%2Ecom|jzqct=/ershoufang/gulou/.jzqsr=nj%2Elianjia%2Ecom|jzqct=/xiaoqu/pg1/; _gat=1; _gat_past=1; _gat_global=1; _gat_new_global=1; _gat_dianpu_agent=1; _smt_uid=59049861.8870a59; CNZZDATA1253492138=835595246-1493470448-null%7C1493541950; CNZZDATA1254525948=1922726511-1493470772-null%7C1493540995; CNZZDATA1255633284=630946367-1493469955-null%7C1493543402; CNZZDATA1255604082=270979082-1493468920-null%7C1493544528; _qzja=1.1520598967.1493473405458.1493480837509.1493544561423.1493544849473.1493544851953.0.0.0.29.3; _qzjb=1.1493544561423.10.0.0.0; _qzjc=1; _qzjto=10.1.0; _jzqa=1.2414222906473966000.1493473537.1493480838.1493544561.3; _jzqc=1; _jzqb=1.10.10.1493544561.1; _ga=GA1.2.1108117219.1493473408; _gid=GA1.2.2091828031.1493544853; lianjia_ssid=5c8ebd96-81f4-4430-bfda-6d941fcb8663')]

	urllib.request.install_opener(opener)

	html_bytes = urllib.request.urlopen(url).read()
	html_string = html_bytes.decode('utf-8')
	return html_string



def start(start_url):
	html_doc = getVillage(start_url)
	soup = BeautifulSoup(html_doc, 'html.parser')

	#获取所有页数和现在页数
	totalPageNoDiv=soup.find("div","house-lst-page-box")
	Page = eval(totalPageNoDiv.attrs['page-data'])

	totalPageNo = Page['totalPage']
	curPage = Page['curPage']

	print('当前正在抓取第'+str(curPage)+'页,共'+str(totalPageNo)+'页.')


	#获取小区内容
	divs = soup.find_all("div","title")
	for div in divs:
		a_tag = div.find("a",target="_blank")
		if(a_tag):
			#插入数据库
			sql = "INSERT INTO `village` (`name`) VALUES (%s)"
			cur.execute(sql, (a_tag.string))

	curPage = curPage + 1;
	if(totalPageNo == curPage-1):
		print('执行完毕.')
	else:
		time.sleep(10)
		start_url = "http://nj.lianjia.com/xiaoqu/pg"+str(curPage)
		start(start_url)


totalPageNo=1
curPage=1

start_url = "http://nj.lianjia.com/xiaoqu/pg"+str(curPage)
start(start_url)


cur.close()#关闭游标
conn.close()#释放数据库资源
__author__='LeoKim'
from bs4 import BeautifulSoup
import pymysql
import urllib.request, urllib.parse, http.cookiejar
from urllib import parse
import pymysql

conn=pymysql.connect(host='localhost',user='root',passwd='superhero',db='python_test',port=3306,charset='utf8')
cur=conn.cursor()#获取一个游标

def getgeohash(keyword):
	key={
		'keyword':keyword
	}


	url='https://mainsite-restapi.ele.me/v2/pois?extras%5B%5D=count&geohash=wtsm0ss7yfj8&limit=20&type=nearby&'+parse.urlencode(key)

	cj = http.cookiejar.CookieJar()
	opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
	opener.addheaders = [('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36'),
	('Cookie', 'ubt_ssid=but8xnmtkpfrbvypd9z3hxaa5i8ugmj0_2017-04-29; _utrace=edd9bb6de13caed667d2cf273d73fc0a_2017-04-29')]

	urllib.request.install_opener(opener)

	html_bytes = urllib.request.urlopen(url).read()
	html_string = html_bytes.decode('utf-8')
	soup = BeautifulSoup(html_string, 'html.parser')

	try:
		info = eval(soup.prettify())
		if len(info) and info is not None:
			return info[0]
		else:
			return 'error'	
	except:
		return 'error'
	

sql = "SELECT id,name FROM `village` where geohash is null"
cur.execute(sql)
data = cur.fetchall()

for d in data:
	print(d[0])

	geohash=''
	latitude=''
	longitude=''

	gh=getgeohash(d[1])

	if gh=='error':
		geohash='error'
		latitude=''
		longitude=''
	else:
		geohash = gh['geohash']
		latitude = gh['latitude']
		longitude = gh['longitude']

	print(geohash,latitude,longitude)

# gh['geohash'] is None

	sql = "UPDATE `village` SET geohash=%s,latitude=%s,longitude=%s where id=%s"
	cur.execute(sql, (geohash,latitude,longitude,d[0]))
	
cur.close()#关闭游标
conn.close()#释放数据库资源
__author__='LeoKim'
from bs4 import BeautifulSoup
import pymysql
import urllib.request, urllib.parse, http.cookiejar
from urllib import parse
import pymysql
import json
import re

conn=pymysql.connect(host='localhost',user='root',passwd='superhero',db='python_test',port=3306,charset='utf8')
cur=conn.cursor()#获取一个游标

def getstore(village_id,geohash,latitude,longitude,limit):
	key={
		'geohash':geohash,
		'latitude':latitude,
		'longitude':longitude,
		'limit':limit
	}


	url='https://mainsite-restapi.ele.me/shopping/restaurants?extras%5B%5D=activities&offset=0&terminal=web'+parse.urlencode(key)

	cj = http.cookiejar.CookieJar()
	opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
	opener.addheaders = [('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36'),
	('Cookie', 'ubt_ssid=but8xnmtkpfrbvypd9z3hxaa5i8ugmj0_2017-04-29; _utrace=edd9bb6de13caed667d2cf273d73fc0a_2017-04-29')]

	urllib.request.install_opener(opener)

	html_bytes = urllib.request.urlopen(url).read()
	html_string = html_bytes.decode('utf-8')
	soup = BeautifulSoup(html_string, 'html.parser')

	info = soup.prettify()
	jsonData = json.loads(info)
	

	for data in jsonData:

		print(data['id'])
		print(village_id)
		print(data['name'])
		print(data['recent_order_num'])
		print(data['address'])
		print(data['order_lead_time'])
		print(data['float_delivery_fee'])

		average_cost=0
		if 'average_cost' in data:
			cost = re.findall(r'\d+', data['average_cost'])
			average_cost=cost[0]
			print(average_cost)

		print(data['rating'])
		print('---------------------------------------------')

		shop_id = data['id']
		name = data['name']
		address = data['address']
		recent_order_num = data['recent_order_num']
		order_lead_time = data['order_lead_time']
		float_delivery_fee = data['float_delivery_fee']
		rating = data['rating']

		sql = "INSERT INTO `store` (`shop_id`,`village_id`,`name`,`address`,`recent_order_num`,`order_lead_time`,`float_delivery_fee`, `average_cost`, `rating`) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)"
		cur.execute(sql, (shop_id,village_id,name, address, recent_order_num, order_lead_time, float_delivery_fee, average_cost, rating))


# getstore('wtst84g4g0u','31.91988','118.83238',30)

sql = "SELECT id,name,geohash,latitude,longitude FROM `village` where id >482 and geohash is not null"
cur.execute(sql)
data = cur.fetchall()

for d in data:
	village_id=d[0]
	geohash = d[2]
	latitude = d[3]
	longitude = d[4]

	getstore(village_id,geohash,latitude,longitude,30)


cur.close()#关闭游标
conn.close()#释放数据库资源

MYSQL mysqldump备份实验

0. meta data lock实现(mysql 5.5后引入的)

http://blog.leokim.cn/2017/05/25/mysql-metadata-lockmdl/

1.分析muysqldump流程

2. 利用mysqldump做备份建一个从库(online不停业务)
3. 理解binary log在备份中的作用
4. 利用全备+binary log恢复到某个时间点
==========
5. 利用innobackupex 做备份及恢复 3307, 3306
6. 利用innobackupext做增备及恢复 3307, 3306
7. 利用innobackupex加binary log恢复到某个时间点

8. 表空间传输5.6, 5.5

扩展知识:

9. 关于mysql 5.5以下mysqlbinlog(第三方版本)的闪回
10. mysql binary logs格式浅析

DDL没办法在事务里保护

blob.png

/usr/local/mysql/bin/mysqldump -S /tmp/mysql_3306.sock –master-data=2 –single-transaction leokim >leokim_1_full.sql

GTID下可以不要"–master-data=2"这个参数

more leokim_1_full.sql

blob.png

blob.png

 人生就这么悲剧了,数据没了,这个时候就需要恢复

需要注意在dump的时候如果是gtid会有一个SET @@GLOBAL.GTID.PURGED 会直接报错

blob.png

mysql -S /tmp/mysql_3306.sock leo_bak<leokim_1_full.sql

 

blob.png

利用全备恢复 但是少了我们全备后添加的memcache

blob.png

在全备文件里找到master_log_pos = 858

所以我们在binlog里找到858这个位置 恢复从这个位置开始 到truncate之间的数据就可以了

blob.png

blob.png

mysqlbinlog -v --base64-output=decode-rows --start-position=858 --stop-position=1149  mybinlog.000001 > 1_bak.sql
use leokim
rename table leo to leo_bak;
rename table leo_bak.leo to leo;
select * from leo;

blob.png

mysqlbinlog --start-position=858 --stop-position=1062  mybinlog.000001 | mysql -S /tmp/mysql_3306.sock

现在看mongodb就恢复出来了

blob.png

如果开启了gtid 要reset master之后再做才行,gtid会认为自己已经做过了就不会恢复

所以恢复要找个别的地方恢复 然后再恢复到主库上 不能在主库上reset master

在测试库里回复完了单独做一次mysqldump 然后到出来放到生产库里恢复

gtid开启的话 要加上-f强制执行

或者加上–set -gtid-purged=OFF

有GTID的环境里做恢复特别要小心

binlog恢复一定要按顺序恢复不能跳着恢复

 

 

python

 r 使用 原始字符串

任意参数的列表

>>> def concat(*args, sep="/"):
...     return sep.join(args)
...>>> concat("earth", "mars", "venus")'
earth/mars/venus'
>>> concat("earth", "mars", "venus", sep=".")'
earth.mars.venus'

分拆参数

>>> list(range(3, 6))            # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args))            # call with arguments unpacked from a list
[3, 4, 5]
>>> def parrot(voltage, state='a stiff', action='voom'):
...     print("-- This parrot wouldn't", action, end=' ')
...     print("if you put", voltage, "volts through it.", end=' ')
...     print("E's", state, "!")
...>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !

SQL四种语言:DDL,DML,DCL,TCL

1.DDL(Data Definition Language)数据库定义语言statements are used to define the database structure or schema.

DDL是SQL语言的四大功能之一。
用于定义数据库的三级结构,包括外模式、概念模式、内模式及其相互之间的映像,定义数据的完整性、安全控制等约束
DDL不需要commit.
CREATE
ALTER
DROP
TRUNCATE
COMMENT
RENAME

2.DML(Data Manipulation Language)数据操纵语言statements are used for managing data within schema objects.

由DBMS提供,用于让用户或程序员使用,实现对数据库中数据的操作。
DML分成交互型DML和嵌入型DML两类。
依据语言的级别,DML又可分成过程性DML和非过程性DML两种。
需要commit.
SELECT
INSERT
UPDATE
DELETE
MERGE
CALL
EXPLAIN PLAN
LOCK TABLE

3.DCL(Data Control Language)数据库控制语言  授权,角色控制等
GRANT 授权
REVOKE 取消授权

4.TCL(Transaction Control Language)事务控制语言
SAVEPOINT 设置保存点
ROLLBACK  回滚
SET TRANSACTION

SQL主要分成四部分:
(1)数据定义。(SQL DDL)用于定义SQL模式、基本表、视图和索引的创建和撤消操作。
(2)数据操纵。(SQL DML)数据操纵分成数据查询和数据更新两类。数据更新又分成插入、删除、和修改三种操作。
(3)数据控制。包括对基本表和视图的授权,完整性规则的描述,事务控制等内容。
(4)嵌入式SQL的使用规定。涉及到SQL语句嵌入在宿主语言程序中使用的规则。

MYSQL 备份

blob.png

blob.png

blob.png

blob.png

blob.png

·  不完全备份(上面少写了)

冷备:把机器关掉 copy数据库文件

热备(hot backup):在数据是运行中,进行的备份

增倍:在上一次备份的基础上做一个增加的备份,今天相对于昨天的变更备份

不完全备份:只备份一张表两张表

blob.png

ntsqldump单进程不太完美

mydumper多进程 sql层备份

xtrabackup基本上大家都在用

在有slave的情景下为什么还要有备份?

人为误操作 在主库上truncate table 从库上也会执行truncate table

mysql 5.6引入delay replication

可以指定从库和主库延迟多长时间 比如说一小时 一小时内主库上有误操作可以不同步到从库上

sql_thread 执行同步 不应用就行了

blob.png

只备份一个表的话只有select权限就可以 如果要一致性就要有lock tables权限

涉及到存储过程和视图就要把show view 和 trigger权限都给上 要不然会报错权限不足

blob.png

造成问题:

  1. 热数据冲掉

  2. 冷数据加载 备份时间长

blob.png

–trigger=false(2个减号)

-t –no-create-info(Don't write table createion info. 不要创建schema) 

-d  不要数据只要表结构

-R存储过程

-n 不要创建库

-E  event 

-f 重置备份

建议每个分开备份 

特别对于数据文件单独放

如果数据库不超过100G 并且内存又很大 可以使用

如果已经100G 内存只有16G 就不要考虑使用mysqldump了

考虑的场景是内存和数据差不多的场景采取用 如果超过3倍以上就不要考虑了 

因为用起来太慢了

blob.png

会有一个问题 如果这个表没有id字段会报错

所以加上where条件的话 要明确这个条件和表是有内容的

mysqldump -t –where="id<10" db1 tb1

这样可以简单的从一个表里拿到一部分去做测试方便拿到子集

DDL不受事务管理 保护不了一致性

一致性快照:拿到一个数据在某一时间一致性的数据 t1时间的备份拿到t1时间的镜像

–set-gtid-purged 会带着gtid的值 表明多少gtid之前的不要了 这样一个标识

默认dump出来的代码:insert into tb1 values(),();

-c参数之后变成:insert into tb1(c1,c2,c3) values(c1,c2,c3);

会变成一个完整的格式,支持对原来表结构进行修改

-h:host

-u :用户

-P:端口号

-p:密码

blob.png

blob.png

不同版本的mysqldump变化很频繁

–replace -> replace into

blob.png

后面再演示

利用mysqldump备份有什么问题?

要注意:

1. 数据的内存的比例

2.mysqldump备份很慢,热数据冲掉冷数据加载时间过程备份时间过长

3.建议只备份数据量小的

4.Innodb表 –single-transanction可以不锁表

5.mysqldump还是单进程的(mydumper多线程并行sql层备份  https://launchpad.net/mydumper)

blob.png

还是基于sql层的备份

blob.png

blob.png

blob.png

mysql本身官方的东西太弱了

很多优秀的东西都是开源的

工具:percona-tools

备份:xtrabackup

监控:zabbix


blob.png

Xtrabackup 是类似于官方的企业备份工具 完全开源

Hot Onloine backup tool for MYSQL

图里的Memory是Innodb Buffer Pool

数据更新时 

1.把数据文件拉到内存更新 

2.把日志写到redo log

3.更新完了再把数据回写到data file里

在一个完整的事务环境保护下作了redo undo相应措施

redo 是为防止在update更新时没有完全提交 崩掉了 可以通过redo 来恢复到数据文件里

image.png

这个16K 是代表page size 可以自己定义

从data file里拿到内存的是page size的大小 这个就是操作最小单位
比如说以下示例:

    select * from user where user_id=100;

    除了会把user_id=100的page全读取到buffer pool里

    还会预读后面的内容 每次取满page size大小

    最小单位基于page size 5.6可以调整

    这个时候就体现出key value缓存的好处

    key value缓存就是一条记录缓存不是基于page的缓存

    没有预读直接获取准确值

    innodb_buffer_pool_size 是基于page的缓存

    每次操作读回来的大小是page size效率上会比key value缓存慢

blob.png

innodb crash recovery

如果更新中挂掉了 可以通过redo log恢复

100G 库 5.5引入innodb fast crash recovery 2,3分钟恢复

5.1之前要很久(1个多小时) 可以在errorlog里可以看到进度

blob.png

在内存里备份的时候先形成xtrabackup log

把数据库的任何变成以redo log的形式写入到xtrabackup log文件里

在这里面把数据文件全部copy走

任何变更都在这个文件里有了

相当于在内存挂掉之后用redo log恢复一下做一次crash recovery恢复

很快把数据文件恢复出来

Xtrabackup其实就时利用innodb的crash recovery原理

blob.png

blob.png

数据恢复是经过内存在内存里合并写入到数据文件里

对一个业务很繁忙的系统备份出来xtrabackup log很大 不要再高峰时间备份

fast recovery 的逻辑

  1. 依赖于redo log(redolog会记录哪个page变更,之后能得到一个page no)

  2. 拿到page no把数据(原始页)从备份的数据里读到内存里

  3. 拿到内存之后修改合并

  4. 持久化到数据文件

blob.png

blob.png

XtraBackup 2.4.1 GA版本发布,终于支持了MySQL 5.7的物理备份

tokudb不支持 可能会按非事务引擎来备份


blob.png

innodb/xtradb可以hot backup

myisam非事务引擎都是要加锁的

blob.png

innobackupex 是调用xtrabackup

中间2个会影响效率不建议使用

xtrabackup不会copy *.frm (表结构文件)

blob.png

ibdata里有什么数据?

1、system tablespace(系统表空间)
ibdata files包含:(共享表空间文件)
(1)、internal data dictionary:数据字典
(2)、insert buffer:插入buffer
(3)、rollback segments:回滚表空间
(3)、undo pages:回滚页
(4)、Double write buffer:写入缓冲区

(5)、undo tablespace 

参照叶的课程

mysql 5.6 引入了一个特性: undo tablespace可以独立配置

blob.png

  1. 先形成xtabackup log文件记录内存里的变更

  2. copy innodb数据文件 .ibd , ibdata1

  3. 设置读锁为了一致性

  4. copy表空间,表结构等文件

  5. 拿到binlog位置

  6. 释放锁

  7. 停掉copy 结束

全事务引擎的–no-lock

blob.png

在做这个的时候是调用xtrabackup来copy的

blob.png

/etc/my.cnf /etc/mysql/my.cnf

/usr/local/mysql/etc/my.cnf

如果不是标准安装需要制定配置文件

指定备份目录

innobackupex –defaults-file=/path/my.cnf /backup/to/path/

依赖变量:

datadir 

socket

如果当前用户连不到mysql里需要提供用户密码

–user=

–password=

–host=

–port=

–apply-log

备份完之后会形成backup-my.cnf

blob.png

数据库刚开始备份时形成xtrabackup_info

xrtabackup_binlog_info: 获得binlog位置show master status的输出

–apply-log之后会形成

xtabackup_slave_info

xtrabackup_binlog_post_innodb

一般情况下xrtabackup_binlog_info应该和xtrabackup_binlog_post_innodb 是相等的

如果不相等以xtrabackup_binlog_post_innodb 为准

xtrabackup_logfile是最早形成的

backup-my.cny有数据库的redu log大小定义

blob.png
    blob.png

blob.png

这里没有gtid比较不爽 不知道现在有没有(https://sanwen8.cn/p/22b9Mii.html)

blob.png

这是测试环境里没有写入 to_lsn和last_lsn是一样的

如果在live里写入会很多 to_lsn和last_lsn会差很大

lsn是log sql no在系统show  engine innodb status\G里面输出

blob.png

其实就是字节大小

blob.png

blob.png

ibdata1:100M:autoextend

被同事改成了1G 

已经完成初始化后,再改,然后重启能不能启动?为什么?

实际的datafile 大于1G可以起来小于1G起不来

ibdata1:10M:autoextend

改小可以起来

因为:定义的值要<=实际的文件 关键在autoextend 只要比定义值小就起不来 大就没问题

innodb_log_file_in_group :log个数

innodb_log_file_size :log大小

这2个参数关系到重新做apply log(好像是这个听的不是太清楚)的时候需要把这2个初始化出来

blob.png

innodb_log_file_size

5.5要重新导入导出重建数据库

5.6可以修改重启就可以了

untitled.bmp

blob.png

指定上一次备份的文件在哪

blob.png

拿到之后主要是找xtabackup_info 找上一次备份的last_lsn找到后把大于这个lsn的data page全部copy一遍,copy到下图位置

blob.png

得到lsn后也可以有偷懒的做法 在做增量备份之前可以指定last_lsn在哪,在这个地方直接指定一个lsn就可一直接备份增量也不用指定上个备份目录在哪,这个做法就是大于这个lsn的page全把他copy一份

这样就是简单的做了一个增量

blob.png

blob.png

恢复:

full_1

incr_1

incr_2

如果incr_1 增量坏了

那就悲剧了

blob.png

data-page, index-page

更紧凑备份:只要data-page不要index-page

恢复的时候要重建index-page

blob.png

innodb_file_per_table:独立表空间

blob.png

include-tables-file=/path/tblist.txt //指定备份哪些表

–database //指定备份哪个库

blob.png

恢复的时候要多一个-export,会多一个tb.exp

紧凑备份

好处是减少备份集,备份小一点

blob.png

紧凑备份恢复的时候要索引重建

blob.png

恢复的时间会比平常时间多好几倍时间 因为索引要重建

========================================================

blob.png

blob.png

export之后除了之前的tb_a.frm, tb_ibd

会生成一个tb_a.cfg

然后把这个文件scp到远程空间上 或者scp到需要导入的那台机器上

导入的机器上需要创建一个同样的表结构

需要把当前表空间干掉blob.png

干掉之后如果没有表空间导进来的话就完蛋了

tb_a.ibd 表空间删掉了

把表空间import进来: alter table tb_a  import tablespace;

这个特性是MySQL 5.6引入的

blob.png

blob.png

基本每天一个全被+每天备份相应的binlog

比如:

早上4点做全备

4点前的binlog也要copy一下

通过天全备+今天的binlog 备份

可以还原到昨天的备份到今天任何一个时间点的备份

还原到今天某个时间点需要什么东西呢?

昨天凌晨4点的全量到今天凌晨4点的全量是什么呢? 是今天今天4点的binlog

重要的放到HDFS上

blob.png

MYSQL SQL编程

blob.png

mysql属于有这些功能但不是强项和分区一样不是特别推荐用

dba不是来写存储过程的 dba主要是是保证性能高可用

更高层面是架构

blob.png

存储过程:一组sql语句在客户端存储待client调用

把这些全封装在数据库里增加了数据库的开销

也可以对一组业务逻辑进行封装

游戏 通过更新存储过程 积分加倍或者不加倍

类型:

1.定义一组sql语句返还结果

2.UDF用户自定义函数 user defined function 函数返回一些标量(不能修改的值)

blob.png

mysql一个sql只能使用一个cpu

sql有没有编译缓存计划? 没有

一组sql在mysql server端运行只在一个核上运行同时没有编译缓存计划那么节省的是什么??

节省是client端向server端传输的网络io 但这个io通常不是我们的瓶颈

唯一我觉得的优点是可以把业务逻辑封装到数据库上

在数据库上通过sql达到业务逻辑的变更

感觉灵活一些

所以建议不要用存储过程 cpu会跑到很高

数据库删除也会删除相应存储过程

blob.png

存储过程是在表里寸的 而且这个表是mysaim的 很操蛋

mysql调存储过程满慢因为缓存不住 其实缓存住 直接在内存拿就好了 这是设计缺陷 后期版本可能会改善 5.7可能会有大的改善

blob.png

delimiter下面定义一个batch sql

create procedure 存储过程名字 括号里可存参数

调用后返回相应3个结果

blob.png

区别是存储函数有一个return 要把结果return回来

blob.png

declare申明的变量是存储过程中的local变量 只在存储过程中有(in可有可无)

declare上面少了个begin

blob.png

使用session变量容易造成结果是乱的慎用出结果特别难查

历史遗留产物

blob.png

blob.png

blob.png

blob.png

blob.png

blob.png

blob.png

blob.png

blob.png

blob.png

调试过程中可以这样看看是哪一步出错了

blob.png blob.png

blob.png

declare “关键词”cursor for "SQL语句"

重点

blob.png

5.6 一个触发器的名字指定定义一个触发器 

5.7这点做了改善 一个触发器可以定义多个

blob.png

高并发环境不允许使用触发器

核心业务里面禁掉不允许

高写入的情况下很耗资源毕竟是多了一些多的操作

blob.png

我们现在考虑都是支持事物的表 

blob.png

blob.png

blob.png

blob.png

级联外键所导致的更改

从库上触发器有可能不起作用

event再从库上也会被disable掉

blob.png

5.1以后才在mysql 引入

应用过程中各种操蛋

打开之后可以通过show processlist;看到多了一个进程

再高可用里切来切去容易造成event丢失

尽可能不用 用定时任务来取代

blob.png

坑:主从库切换之后 从库上的event是不会运行的

提升为主库也不会运行

需要把slave side去掉 然后out 一下inable

blob.png

blob.png

blob.png

MySQL分区

blob.png

SQL优化的核心:

减少I/0

把随机IO转成顺序IO

分区唯一的场景:用来记日志

blob.png

mysql hash分区 要求分区表达式必须是整数

range, list, hash

blob.png

show variables like "%partition%";

mysql 5.1 开始支持分区

blob.png

SELECT * FROM `PLUGINS` WHERE PLUGIN_NAME LIKE '%partition%'\G

mysql的分区比oracle差距很大 很弱

好处是从官方手册里直接翻译过来的,老师说不要用分区哈哈哈哈

特别不重要的地方才用分区,比如说日志

blob.png

delete from tb where add_date<'';

数据量太大删除不掉

用分区drop很方便

alter table tb drop partition p1;

blob.png

5.6种可以自动判断不用显示声明

innodb必须有主键

主键又必须在你的分区表达式里

blob.png

blob.png

range(year(add_datetime))

range columns(date(add_datetime))

partition p0 values less than ('2017-01-01'),

blob.png

blob.png

blob.png

list就是一个集合(有限的集合)

blob.png

blob.png

blob.png

blob.png

blob.png

blob.png

blob.png

blob.png

blob.png

blob.png

子分区名字不能重复

blob.png

blob.png

blob.png

blob.png

blob.png

group_concat长度有限制 可以修改

show global variables like "%group%";

blob.png

入果只命中一个效率最高

blob.png

blob.png

blob.png

blob.png

blob.png

blob.png

blob.png 

blob.png

blob.png

blob.png

blob.png

blob.png

mysql partition没有全局索引,所以索引都在自己的ipdate里放

一个分区一个索引没有完整性

blob.png

blob.png

mysql分区没有全局索引

分区能不能达到行级锁呢?

如果要有行级锁需要针对主键或者针对唯一索引

那么这个主键或者唯一索引就有一个条件必须在分区表达式里面

range 必须by primary key 或者 unique key

如果条件能去where的主键或者unique key那么能做行级锁

如果不能基本上是去锁到一个很大的区间

分区表包括mysql的表在select期间是不能去修改表的结构的

在执行代码的过程中是锁定的

锁定表的结构

这个是由存储引擎来处理不允许更改表结构

因为这个锁是存储引擎自己来处理的 所以每个存储引擎处理的方式也不同

myisam就是全局的锁等待

innodb通过不断重试去拿锁

每个分区都是一个存储引擎的实例 他们都有自己的ibdata

blob.png

其实对锁的粒度还是挺粗的 动不动就是一个range 锁

blob.png

不能对临时表进行分区 上面ppt日志写错了

blob.png

大部分都是时间函数,Mysql就是提倡对时间类的数据进行分期的

可用,但不可以委以重任

blob.png

不要再更改sql model

MYSQL基于复制业界的一些新技术

blob.png

blob.png

blob.png

master挂了

现在要提升slave为master 要做一些同步对比

以下要熟记,是最基础的

第一: 要确认自已是同步完成的 

master_log_file == relay_master_log_file 和read_master_log_pos =exec_master_log_pos

第二: 要确认slave1和slave2是相等的

slave1.master_log_file == slave2.master_log_file || slave1.master_log_pos == slave2.master_log_pos

第三: 让slave2 change 到slave1上

slave1(在即将成为master的slave上): 上执行一个show master status;

如果是GTID的直接change过去就OK了

show processlist查看master上的slave(和此文无关)

slave2: 执行一下show slave status;

slave2 : stop slave; change master ; start slave; show slave status;

reset slave; 清掉本地的relay log , 把同步调整到起始位置

blob.png

字典表

比如说 地理信息

blob.png

blob.png

多机房同步

blob.png

blob.png

blob.png

blob.png

blob.png

blob.png

blob.png

选择proxy:

这个proxy有没有维护了,自已能不能维护