事务是数据库并发控制的基本单位 事务能够看做是一些列SQL语句的集合 事务必需要么所有执行成功,要么所有执行失败(回滚) 事务使用常见的场景:银行转帐操做
原子性(Atomicity):一个事务中全部操做所有完成或失败 一致性(Consistency):事务开始和结束以后数据完整性没有被破坏 隔离性(Isolation):容许多个事务同时对数据库修改和读写 持久性(Durability):事务结束以后,修改是永久的不会被丢失
幻读:一个事务第二次查出现第一次没有的结果 非重复读:一个事务重复读两次获得不一样的结果 脏读:一个事务读取到另外一个事务没有提交的修改 丢失修改:并发写入形成其中一些修改丢失
读未提交:别的事务能够读取到未提交改变 读已提交:只能读取已经提交的数据 可重复读:同一个事务前后查询结果同样(Mysql innoDB默认实现可重复读级别) 串行化: 事务彻底串行化执行,隔离级别最高,效率最低
使用数据库的惟一索引 使用队列异步写入 使用redis等实现分布式锁
悲观锁:先获取锁再进行操做。一锁二查三更新 select for update 乐观锁:先修改,更近的时候发现数据已经变了就回滚(check and set) 使用须要根据响应速度、冲突频率、重试代价来判断使用哪种
CHAR VARCHAR TINYTEXT TEXT
TINYINT SMALLINT INT SIGINT FLOAT DOUBLE
DATE DATETIME TIMESTAMP (4个字节,但接受的时间1970-2038年之间)
MyISAM不支持事务,InnoDB支持事务 MyISAM不支持外键,InnoDB支持外键 MyISAM只支持表锁,InnoDB支持行锁和表锁 MyISAM支持全文索引,InnoDB不支持
数据表种一个或者多个列进行排序的数据结构 索引可以大幅提高索引速度 建立、更新索引自己也会消耗空间和时间
多路平衡查找树
Mysql实际使用的B+Tree做为索引的数据结构
普通索引 CREATE INDEX 惟一索引,索引列的值必须惟一 CREATE UNIQUE INDEX 多列索引(联合索引) 主键索引 一个表只能有一个 PRIMARY KEY 全文索引 InnoDB不支持(通常采用专门的全文索引数据库实现)
常常用做查询条件的字段(WHERE条件) 常常用做表链接的字段 常常出如今order by, group by以后的字段
非空字段NOT NULL, Mysql很难对空值作查询优化 区分度高,离散度大,做为索引的字段值尽可能不要有大量相同值 索引的长度不要太大(比较消耗时间--索引做为B+Tree的key值存在,字符串key太长比较耗时)
记忆口诀:模型匹配、类型隐转、最左匹配 以%开头的LIKE语句,模糊搜索 出现隐式转换(python这种动态语言查询中须要注意) 没有知足最左前缀原理(针对联合索引)
是指B+Tree叶节点存的是指针仍是数据记录 MyISAM索引和数据分离,使用的是非汇集索引(存的是数据指针) InnoDB数据文件就是索引文件,主键索引就是汇集索引
slow_query_log_file开启而且查询慢查询日志 经过explain命令排查索引问题 调整数据修改索引;业务代码层限制不合理访问(好比一次获取太多数据--实现分页; 数据类型不匹配致使全文扫描)
内链接(INNER JOIN):两个表都存在匹配时,才会返回匹配行 外链接(LEFT/RIGHT JOIN): 返回一个表的行,即便另外一个没有匹配 全链接(FULL JOIN):只要某一个表存在匹配就返回
缓解关系数据(常见的Mysql)并发访问的压力: 热点数据 减小响应时间:内存IO速度比磁盘快 提高吞吐量: Redis等内存数据库单机就能够支持很大并发
数据存储类型:redis支持string/List/hash/set/sort set;memcached只支持文本型/二进制类型 网络IO模型:redis单进程模式;memcached多线程、非阻塞IO模式 持久化支持:redis支持两种RDB,DOF; memcached不支持
String(字符串):用来实现简单的KV键值对存储,好比计数器
List(链表): 实现双向链表,好比用户的关注,粉丝列表
Hash(哈希表):用来存储彼此相关信息的键值对
Set(集合): 存储不重复元素,好比用户的关注者
Sorted set(有序集合): 实时信息排行榜python
快照方式:把树快照放在磁盘二进制文件中,dump.rdb AOF: 每个写命令追加到appendonly.aof中 能够修改经过Redis配置实现
将多个请求打包,一次性,按序执行多个命令的机制 经过 MULTI, EXEC,WATCH等命令实现事务功能
使用setnx实现加锁,能够同时经过expire添加超时时间 锁的value值可使用一个随机的uuid或者特定的命名 释放锁的时候,经过uuid判断是不是该锁,是则执行delete释放锁
Cache Aside: 同时更新缓存和数据库 Read/Write Through: 先更新缓存,缓存负责同步更新数据库 Write Behind Caching: 先更新缓存,缓存按期异步更新数据库
缘由:因为大量缓存查不到就去数据库取,数据库也没有要查的数据 解决:对于没有查到返回None的数据也缓存; 插入数据的时候删除相应缓存,或者设置较短的超时时间
缘由:某些很是热点的数据key过时,大量请求达到后端数据库 解决: 分布式锁-获取锁的线程从数据库拉数据更新缓存,其余线程等待 异步后台更新-后台任务针对过时key自动刷新
缘由:缓存不可用或大量缓存key同时失效,大量请求直接达到数据库 解决: 多级缓存--不一样级别的key设置不一样的超时时间 随机超时--key的超时时间随机设置,防止同时超时 架构层--提高系统可用性,监控、报警完善
在最佳实践中,auto_increment字段长度比uuid小,从性能及可读性都比uuid要好
在auto_increment的基础上,设置step增加步长;好比:Master1 生成的是 1,4,7,10, Master2生成的是2,5,8,11 Master3生成的是 3,6,9,12。 这样就能够有效生成集群中的惟一ID,也能够大大下降ID生成数据库操做的负载。
编写一个简单的分布式锁,要求支持超时时间参数
import time import redis class RedisLock(object): def __init__(self, key, timeout): self.rdcon = redis.Redis(host='', port=6379, password="", db=1) self._lock = 0 self.timeout = timeout self.lock_key = "%s_dynamic_test" % key @staticmethod def get_lock(cls): while cls._lock != 1: timestamp = time.time() + self.timeout + 1 cls._lock = cls.rdcon.setnx(cls.lock_key, timestamp) # 注意下方括号的范围 if cls._lock == 1 or (time.time() > cls.rdcon.get(cls.lock_key) and time.time() > cls.rdcon.getset(cls.lock_key, timestamp)): print "get lock" break else: time.sleep(0.3) @staticmethod def release(cls): if time.time() < cls.rdcon.get(cls.lock_key): print("release lock") cls.rdcon.delete(cls.lock_key) def deco(cls): def _deco(func): def __deco(*args, **kwargs): print("before %s called [%s]."%(func.__name__, cls)) cls.get_lock(cls, timeout) try: return func(*args, **kwargs) finally: cls.release(cls) return __deco return _deco @deco(RedisLock("key")) def myfunc(): # do_something time.sleep(20) if __name__ == "__main__": myfunc()