索引/连接池/缓存
时间:2023-01-26 07:00:00
常见的数据库问题
索引的功能和原理
实际上,索引也是一张表,该表保存了主键与索引并指向实体表的记录。
索引也有它的缺点:虽然索引很大提高查询速度,降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存索引文件。
索引文件的建立将占用磁盘空间。
为何能提高查询速度?
索引就是提前排序,因此,它可以应用于搜索二分搜索等高效算法。
一般顺序搜索,复杂度为O(n),而二分搜索的复杂为O(log2n)。当n很大时,两者的效率差异及其悬殊。
举个例子:
表中有100万条数据需要找到一个特定的数据id数据。如果按顺序搜索,平均需要搜索50万个数据。而且用二分法,最多不超过20次就能找到。效率差2.5万倍!
当需要频繁使用一个或一些字段作为查询条件,并且有更多的表数据时,创建索引将显著提高查询速度,因为它可以从整个表扫描改为索引扫描。
(无索引时,全表面扫描即逐一扫描全部记录,直符合条件,索引扫描可直接定位)
索引有副作用吗?
(1)索引是在有大量数据的时候建立起来的,没有大量数据会浪费时间,因为索引是用来的二叉树建立.
(2)当系统查询频繁,新建、修改等操作较少时,可以创建索引,使查询速度比以前快得多,但也带来缺点,即新建或修改,比没有索引或没有覆盖索引慢。
(3)索引越多越好。索引太多会占用很多索引表空间,甚至比存储记录还要多。
对于需要频繁添加记录的表,最好不要创建索引,执行没有索引的表insert、append很快,有了索引,就会有更多的维护索引操作,一些大表可能会导致insert 速度很慢。
最左前缀原则是什么?
MySQL中间的索引可以按一定顺序引用多列,称为联合索引。如User表的name和city加联合索引就是(name,city),最左前缀原则是指如果查询条件与索引左侧连续一列或几列准确匹配,则可以使用此列。
select * from user where name=xx and city=xx ; //可以命中索引
select * from user where name=xx ; // 可以命中索引
select * from user where city=xx ; // 无法命中索引
需要注意的是,如果在查询时使用了两种条件,但顺序不同,如 city= xx and name =xx,然后,当前的查询引擎将自动优化为匹配联合索引的顺序,以便命中索引。
**由于最左前缀原则,在创建联合索引时,索引字段的顺序需要考虑字段值的数量,更多地放在前面。**ORDER BY子句也遵循这一规则。
Mysql如何向表字段添加索引?
1.添加PRIMARY KEY(主键索引)
ALTER TABLE ‘table_name’ ADD PRIMARY KEY ( ‘column’ )
2.添加UNIQUE(唯一索引)
ALTER TABLE ‘table_name’ ADD UNIQUE ( ‘column’ )
3.添加INDEX(普通索引)
ALTER TABLE ‘table_name’ ADD INDEX index_name ( ‘column’ )
4.添加FULLTEXT(全文索引)
ALTER TABLE ‘table_name’ ADD FULLTEXT ( ‘column’ )
5.添加多列索引
ALTER TABLE ‘table_name’ ADD INDEX index_name ( ‘column’ )
如何优化大表
-
限制数据的范围
一定要禁止没有任何限制数据范围的查询语句。例如,当用户查询订单历史时,我们可以控制在一个月内; -
读/写分离
经典的数据库拆分方案,主库负责写,主库负责读; -
垂直分区
根据数据库中数据表的相关性进行拆分。 例如,用户表中既有用户的登录信息,也有用户的基本信息,用户表可以分成两个单独的表,甚至放在单独的库中作为分库。
简单来说垂直拆分是指数据表的拆分,将一个列较多的表分为多个表。
垂直拆分的优点: 它可以减少列数据,减少查询时的读取Block数,减少I/O次数。此外,垂直分区可简化表面结构,易于维护。
垂直拆分的缺点: 主键会出现冗余,需要管理冗余列,造成Join可在应用层操作Join来解决。垂直分区会使事务变得更加复杂;
- 水平分区
通过某种方式保持数据表结构不变数据分片的策略存储。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。 水平拆分可以支持大量数据。
水平拆分是指数据表行的拆分,当表行数超过200万行时,会变慢,此时,可以将一张表的数据拆分成多个表来存储。例如,我们可以将用户信息表分成多个用户信息表,以避免单个表数据量过大对性能的影响。
水平分割可以支持大量的数据。需要注意的是,分表只解决了单表数据过多的问题,但由于表数据仍在同一台机器上,实际上是为了改进MySQL并发能力没有意义,所以 水平拆分最好分库 。
水平拆分可以 支持大量数据存储,应用端改造也很少,但 分片事务难以解决 ,跨节点Join性能差,逻辑复杂。《Java作者推荐工程师修炼之道 尽量不要分割数据,因为分割会带来逻辑、部署、操作和维护的各种复杂性 ,一般数据表在适当优化的情况下支持数千万以下的数据量并不是什么大问题。如果您真的想分割,请尝试选择客户端的分割架构,以减少一次和中间部件的网络I/O。
数据库连接池
池化设计不应该是新名词。我们很常见java线程池、jdbc连接池、redis这种设计代表了连接池等。这种设计将最初预设资源,解决的问题是抵消每次获取资源的消耗,如创建线程和获取远程连接的费用等。就像你去食堂做饭一样,做饭的阿姨会先在那里放几份饭。当你来的时候,你可以直接拿着饭盒加蔬菜。如果你不需要临时吃饭和做饭,效率会很高。池化设计除初始化资源外,还包括以下特点:池的初始值、池的活跃值、池的最大值等,可直接映射到java在线程池和数据库连接池的成员属性中。——本文介绍了池化设计理念,直接复制,避免重复轮。
[https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485679&idx=1&sn=57dbca8c9ad49e1f3968ecff04a4f735&chksm=cea24724f9d5ce3212292fac291234a760c99c0960b5430d714269efe33554730b5f71208582&token=1141994790&lang=zh_CN#rd]:
数据库连接的本质是 socket 的连接。数据库服务端还需要维护一些缓存和用户权限信息 所以占用了一些内存。我们可以把数据库连接池被视为维护数据库连接的缓存,这样这些连接就可以在未来需要对数据库的要求时重用。打开和维护每个用户的数据库连接,特别是动态数据库驱动的网站应用程序,既昂贵又浪费资源。在连接中,创建连接后,将其放置在池中,并再次使用它,因此不必建立新的连接。如果使用了所有连接,则会建立一个新连接并将其添加到池中。连接池还减少了用户必须等待建立与数据库的连接的时间。
为什么要用Redis 为什么要用缓存
主要从“高性能”和“高并发”这两点来看待这个问题。
高性能:
假如用户第一次访问数据库中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。将该用户访问的数据存在缓存中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可!
高并发:
直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。
什么是雪崩以及如何解决?
简介:缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
有哪些解决办法?
事前:尽量保证整个 redis 集群的高可用性,发现机器宕机尽快补上。选择合适的内存淘汰策略。
事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL崩掉
事后:利用 redis 持久化机制保存的数据尽快恢复缓存
Hystrix [hɪst’rɪks],中文含义是豪猪,因其背上长满棘刺,从而拥有了自我保护的能力。本文所说的Hystrix是Netflix开源的一款容错框架,同样具有自我保护能力。为了实现容错和自我保护,下面我们看看Hystrix如何设计和实现的。
Hystrix设计目标:
对来自依赖的延迟和故障进行防护和控制——这些依赖通常都是通过网络访问的
阻止故障的连锁反应
快速失败并迅速恢复
回退并优雅降级
提供近实时的监控与告警
Hystrix遵循的设计原则:
防止任何单独的依赖耗尽资源(线程)
过载立即切断并快速失败,防止排队
尽可能提供回退以保护用户免受故障
使用隔离技术(例如隔板,泳道和断路器模式)来限制任何一个依赖的影响
通过近实时的指标,监控和告警,确保故障被及时发现
通过动态修改配置属性,确保故障及时恢复
防止整个依赖客户端执行失败,而不仅仅是网络通信
Hystrix如何实现这些设计目标?
使用命令模式将所有对外部服务(或依赖关系)的调用包装在HystrixCommand或HystrixObservableCommand对象中,并将该对象放在单独的线程中执行;
每个依赖都维护着一个线程池(或信号量),线程池被耗尽则拒绝请求(而不是让请求排队)。
记录请求成功,失败,超时和线程拒绝。
服务错误百分比超过了阈值,熔断器开关自动打开,一段时间内停止对该服务的所有请求。
请求失败,被拒绝,超时或熔断时执行降级逻辑。
近实时地监控指标和配置的修改。