掘地三尺搞定 Redis 与 MySQL 数据一致性问题
Redis 拥有高性能的数据读写功能,被我们广泛用在缓存场景,一是能提高业务系统的性能,二是为数据库抵挡了高并发的流量请求。 把 Redis 作为缓存组件,需要防止出现以下问题,否则可能会造成生产事故。 Redis 缓存满了 缓存穿透、缓存击穿、缓存雪崩 Redis 数据过期了 Redis 突然变慢了 Redis 与 MySQL 数据一致性问题 在本文正式开始之前,需要大家先取得以下两点共识: 缓存必须要有过期时间; 保证数据库跟缓存的最终一致性即可,不必追求强一致性。 1. 什么是数据库与缓存一致性? 数据一致性指的是: 缓存中存有数据,缓存的数据值 = 数据库中的值; 缓存中没有该数据,数据库中的值 = 最新值。 反推缓存与数据库不一致: 缓存的数据值 ≠ 数据库中的值; 缓存或者数据库存在旧的数据,导致线程读取到旧数据。 为何会出现数据一致性问题呢? 把 Redis 作为缓存的时候,当数据发生改变我们需要双写来保证缓存与数据库的数据一致性。 数据库跟缓存毕竟是两套系统,如果要保证强一致性,势必要引入 2PC 或 Paxos 等分布式一致性协议,或者分布式锁等等。这个在实现上是有难度的,而且一定会对性能有影响。 如果真的对数据的一致性要求这么高,那引入缓存是否真的有必要呢? 2. 缓存的使用策略 在使用缓存时,通常有以下几种缓存使用策略用于提升系统性能: Cache-Aside 模式(旁路缓存,业务系统常用) Read-Through 模式(直读) Write-Through 模式(同步直写) Write-Behind 模式 2.1 […]
MySQL创建用户与授权方法
一, 创建用户: 命令:CREATE USER ‘username’@’host’ IDENTIFIED BY ‘password’; 说明:username – 你将创建的用户名, host – 指定该用户在哪个主机上可以登陆,如果是本地用户可用localhost, 如果想让该用户可以从任意远程主机登陆,可以使用通配符%. password – 该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器. 例子: CREATE USER ‘dog’@’localhost’ IDENTIFIED BY ‘123456’; CREATE USER ‘pig’@’192.168.1.101_’ IDENDIFIED BY ‘123456’; CREATE USER ‘pig’@’%’ IDENTIFIED BY ‘123456’; CREATE USER ‘pig’@’%’ IDENTIFIED BY ”; CREATE USER ‘pig’@’%’; 二,授权: 命令:GRANT privileges ON databasename.tablename TO ‘username’@’host’ 说明: privileges […]
打开MySQL数据库远程访问的权限
Mysql为了安全性,在默认情况下用户只允许在本地登录,可是在有此情况下,还是需要使用用户进行远程连接,因此为了使其可以远程需要进行如下操作: 一、允许root用户在任何地方进行远程登录,并具有所有库任何操作权限,具体操作如下: 在本机先使用root用户登录mysql: mysql -u root -p”youpassword” 进行授权操作: mysql>GRANT ALL PRIVILEGES ON *.* TO ‘root’@’%’ IDENTIFIED BY ‘youpassword’ WITH GRANT OPTION; 重载授权表: FLUSH PRIVILEGES; 退出mysql数据库: exit 二、允许root用户在一个特定的IP进行远程登录,并具有所有库任何操作权限,具体操作如下: 在本机先使用root用户登录mysql: mysql -u root -p”youpassword” 进行授权操作: GRANT ALL PRIVILEGES ON *.* TO root@”172.16.16.152″ IDENTIFIED BY “youpassword” WITH GRANT OPTION; 重载授权表: FLUSH PRIVILEGES; 退出mysql数据库: exit 三、允许root用户在一个特定的IP进行远程登录,并具有所有库特定操作权限,具体操作如下: 在本机先使用root用户登录mysql: mysql -u […]
SQLSERVER建立索引 注意的问题
人们在使用SQL时往往会陷入一个误区,即太关注于所得的结果是否正确,而忽略了不同的实现方法之间可能存在的 性能差异,这种性能差异在大型的或是复杂的数据库环境中(如联机事务处理OLTP或决策支持系统DSS)中表现得尤为明 显。笔者在工作实践中发现,不良的SQL往往来自于不恰当的索引设计、不充份的连接条件和不可优化的where子句。在对 它们进行适当的优化后,其运行速度有了明显地提高!下面我将从这三个方面分别进行总结: —- 为了更直观地说明问题,所有实例中的SQL运行时间均经过测试,不超过1秒的均表示为(< 1秒)。 —- 测试环境– —- 主机:HP LH II —- 主频:330MHZ —- 内存:128兆 —- 操作系统:Operserver5.0.4 —-数据库:Sybase11.0.3 一、不合理的索引设计 —-例:表record有620000行,试看在不同的索引下,下面几个 SQL的运行情况: —- 1.在date上建有一个非群集索引 select count(*) from record where date >’19991201′ and date < ‘19991214’and amount >2000 (25秒) select date,sum(amount) from record group by date(55秒) select count(*) from record where date >’19990901′ and place in (‘BJ’,’SH’) (27秒) —- 分析: —-date上有大量的重复值,在非群集索引下,数据在物理上随机存放在数据页上,在范围查找时,必须执行一次表扫描才能找到这一范围内的全部行。 —- 2.在date上的一个群集索引 select count(*) from record where date >’19991201′ and date < ‘19991214’ and amount >2000(14秒) select date,sum(amount) from record group by date(28秒) select count(*) from record where date >’19990901′ and place in (‘BJ’,’SH’)(14秒) —- 分析: —- 在群集索引下,数据在物理上按顺序在数据页上,重复值也排列在一起,因而在范围查找时,可以先找到这个范围的起末点,且只在这个范围内扫描数据页,避免了大范围扫描,提高了查询速度。 —- 3.在place,date,amount上的组合索引 select count(*) from record where date >’19991201′ and date < ‘19991214’ and amount >2000(26秒) select date,sum(amount) from record group by date(27秒) select count(*) from record where date >’19990901′ and place in (‘BJ, ‘SH’)(< 1秒) —- 分析: —- 这是一个不很合理的组合索引,因为它的前导列是place,第一和第二条SQL没有引用place,因此也没有利用上索引;第三个SQL使用了place,且引用的所有列都包含在组合索引中,形成了索引覆盖,所以它的速度是非常快的。 —- 4.在date,place,amount上的组合索引 select count(*) from record where date >’19991201′ and date < ‘19991214’ and amount >2000(< 1秒) select date,sum(amount) from record group by date(11秒) select count(*) from record where date >’19990901′ and place in (‘BJ’,’SH’)(< 1秒) —- 分析: —- 这是一个合理的组合索引。它将date作为前导列,使每个SQL都可以利用索引,并且在第一和第三个SQL中形成了索引覆盖,因而性能达到了最优。 —- 5.总结: —- 缺省情况下建立的索引是非群集索引,但有时它并不是最佳的;合理的索引设计要建立在对各种查询的分析和预测 上。一般来说: —- ①.有大量重复值、且经常有范围查询 (between, >,< ,>=,< =)和order by 、group by发生的列,可考虑建立群集索引; —- ②.经常同时存取多列,且每列都含有重复值可考虑建立组合索引; —- ③.组合索引要尽量使关键查询形成索引覆盖,其前导列一定是使用最频繁的列。 二、不充份的连接条件: —- 例:表card有7896行,在card_no上有一个非聚集索引,表account有191122行,在 account_no上有一个非聚集索引,试看在不同的表连接条件下,两个SQL的执行情况: select sum(a.amount) from account a,card b where a.card_no = b.card_no(20秒) —- 将SQL改为: select sum(a.amount) from account a,card b where a.card_no = b.card_no and a.account_no=b.account_no(< 1秒) —- 分析: —- 在第一个连接条件下,最佳查询方案是将account作外层表,card作内层表,利用card上的索引,其I/O次数可由以下公式估算为: —- 外层表account上的22541页+(外层表account的191122行*内层表card上对应外层表第一行所要查找的3页)=595907次I/O —- 在第二个连接条件下,最佳查询方案是将card作外层表,account作内层表,利用account上的索引,其I/O次数可由以下公式估算为: —- 外层表card上的1944页+(外层表card的7896行*内层表account上对应外层表每一行所要查找的4页)= 33528次I/O […]
SQL数据库查询语句/连接查询/多表连接查询
一、 简单查询 简单的Transact-SQL查询只包括选择列表、FROM子句和Where子句。它们分别说明所查询列、查询的表或视图、以及搜索条件等。 例如,下面的语句查询testtable表中姓名为“张三”的nickname字段和email字段。 Select nickname,email FROM testtable Where name=’张三’ (一) 选择列表 选择列表(select_list)指出所查询列,它可以是一组列名列表、星号、表达式、变量(包括局部变量和全局变量)等构成。 1、选择所有列 例如,下面语句显示testtable表中所有列的数据: Select * FROM testtable 2、选择部分列并指定它们的显示次序 查询结果集合中数据的排列顺序与选择列表中所指定的列名排列顺序相同。例如: Select nickname,email FROM testtable 3、更改列标题 在选择列表中,可重新指定列标题。定义格式为: 列标题=列名 列名 列标题 如果指定的列标题不是标准的标识符格式时,应使用引号定界符,例如,下列语句使用汉字显示列标题: Select 昵称=nickname,电子邮件=email FROM testtable 4、删除重复行 Select语句中使用ALL或DISTINCT选项来显示表中符合条件的所有行或删除其中重复的数据行,默认为ALL。使用DISTINCT选项时,对于所有重复的数据行在Select返回的结果集合中只保留一行。 5、限制返回的行数 使用TOP n [PERCENT]选项限制返回的数据行数,TOP n说明返回n行,而TOP n PERCENT时,说明n是表示一百分数,指定返回的行数等于总行数的百分之几。例如: Select TOP 2 *FROM testtable Select TOP 20 PERCENT * FROM testtable (二) FROM子句 FROM子句指定Select语句查询及与查询相关的表或视图。在FROM子句中最多可指定256个表或视图,它们之间用逗号分隔。 在FROM子句同时指定多个表或视图时,如果选择列表中存在同名列,这时应使用对象名限定这些列所属的表或视图。例如在usertable和citytable表中同时存在cityid列,在查询两个表中的cityid时应使用下面语句格式加以限定: Select username,citytable.cityid FROM usertable,citytable Where usertable.cityid=citytable.cityid 在FROM子句中可用以下两种格式为表或视图指定别名: 表名 as 别名 表名 别名 例如上面语句可用表的别名格式表示为: Select username,b.cityid FROM usertable a,citytable b Where a.cityid=b.cityid Select不仅能从表或视图中检索数据,它还能够从其它查询语句所返回的结果集合中查询数据。例如: Select a.au_fname+a.au_lname FROM authors a,titleauthor ta (Select title_id,title FROM titles Where ytd_sales>10000 ) AS t Where a.au_id=ta.au_id AND ta.title_id=t.title_id […]