-
2018-05-23 10:09:11
mysql使用索引能提高查询效率,但在有些情况下,你使用索引查询,索引并没有起作用。
mysql> select * from stu; +------+------+----------+ | id | age | name | +------+------+----------+ | 1 | 1 | zhangsan | | 2 | 2 | lisi | | 3 | 3 | wangwu | | 4 | 4 | zhaoliu | | 5 | 5 | sunqi | +------+------+----------+ 5 rows in set (0.00 sec) mysql> show index from stu; +-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | stu | 1 | index_name | 1 | name | A | 5 | NULL | NULL | YES | BTREE | | | +-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 1 row in set (0.00 sec)
可以看到stu表中的name字段为该表的索引。
mysql> explain select * from stu where name like 'z%'; +----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | stu | NULL | range | index_name | index_name | 23 | NULL | 2 | 100.00 | Using index condition | +----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+-----------------------+ 1 row in set, 1 warning (0.00 sec) mysql> explain select * from stu where name like '%i'; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | stu | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 20.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
由结果可以看到,like 'z%'使用了索引查询,而like '%i'没有使用索引查询。key为index_name表示使用了索引查询。
关于like的查询:如果匹配字串的第一个字符为'%',索引不会起作用。只有'%'不在第一个位置,索引才会起作用。
mysql> create index index_id_age on stu(id,age); Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> show index from stu; +-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | stu | 1 | index_id_age | 1 | id | A | 5 | NULL | NULL | YES | BTREE | | | | stu | 1 | index_id_age | 2 | age | A | 5 | NULL | NULL | YES | BTREE | | | +-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 2 rows in set (0.00 sec) mysql> explain select * from stu where id=4; +----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------+ | 1 | SIMPLE | stu | NULL | ref | index_id_age | index_id_age | 5 | const | 1 | 100.00 | NULL | +----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec) mysql> explain select * from stu where age=4; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | stu | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 20.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
我们为表stu创建了一个多列索id和age。当我们单独使用id时,查询使用了索引;而当单独使用age时,查询没有使用索引。则对应多列索引,只有当查询使用了这些字段的第一个字段时,索引才会被使用。
当查询条件使用or关键字时,且or前后的两个条件中的列都是索引时,查询中才使用索引。否则将不使用索引。
我目前机器上测试的结果是:or前后都使用索引,查询还是不用索引,不知何故。感兴趣的读者可以在自己mysql上尝试一下。
参考资料:mysql从入门到精通
更多相关内容 -
修复表索引损坏无法打开的问题
2015-11-23 18:17:26修复表索引损坏无法打开的问题 -
elasticSearch -- (文档,类型,索引)
2021-11-12 14:48:28分词索引 当温度经过0~n个分词过滤器后,将发送到lucene进行文档索引。 以上所有的不同组件部分组成了一个分析器(analyzer),Elasticsearch提供了很多这种分析器可以直接使用而不用构建自己的分析器 内置分析器 ...问题:大规模数据如何检索
- 当系统数据量达到10亿,100亿级别的时候,我们系统该如何去解决这种问题。
- 数据库选择—mysql, sybase,oracle,mongodb,hbase…
- 单点故障如何解决—lvs, F5,A10,Zookeeper,MQ
- 如何保证数据安全----热备,冷备,异地多活
- 如何解决检索难题—数据库中间件mysql-proxy,sharding, cobar, MaxScale
- 如何积极统计分析问题—离线计算,近实时
- 传统数据库的应对解决方案,对于关系型数据库,通常用以下架构解决查询瓶颈
- 通过主从备份解决数据安全性问题
- 通过数据库代理中间件心跳检测,解决单点故障问题
- 通过代理中间件将查询语句分发到每个slave节点查询,并且汇总结果
- 非关系型数据库解决方案,用MongoDB为案例,其他的原理类似
- 通过副本备份积极数据安全性问题
- 通过节点竞选机制解决单点问题
- 先从配置库检索分片信息,让后请求分发到各个节点,最后由路由节点合并汇总结果。
- 用内存数据库
- 不可能完全在内存中放所有数据,单达到PB级别的时候,每个节点按256G,在内存完全装满情况下我们需要如下个机器 1PB = 1024T = 1024*1024G,节点1024 * 4 = 4096个,加上备份的数据,节点应该会超过4096 * 2 = 8192个,太费钱
- 不管是否全部放内存都不能完全解决问题,用一下方式
- 存储数据按有序存储
- 将数据和索引分离、
- 压缩数据
luncene与 ES
- luncene只是一个检索库,要想使用必须用java开发并且集成到你项目中,并且luncene非常复杂,需要深入了解检索的相关知识来理解他是如何工作的。
- Elasticsearch使用luncene作为底层查询,用java开发,通过RESTful api来隐藏Lucene的复杂性,使用只需关注api就行,降低接入成本以及复杂度。
ES主要解决问题
- 检索相关数据
- 返回统计结果
- 速度快
原理
- 当ElasticSearch的节点启动后,会利用多播(multicast)或者单播(配置修改)寻找集群中其他节点,并且建立连接,过程如下:
核心概念
- 集群:ES可以作为独立的搜索服务器,不过处理的数据局限于单点存储功能,可以通过多借点相互合作的多服务器上,实现大小数据集检索,实现容错和高可用。
- 分片:文档巨大,内存限制,磁盘处理能力不足,无法足够快的响应查询,一个节点存储不够。这些情况,数据可以分开成多个较小的分片,每个分片在不同的服务器上。单查询的索引分布在多个分片上,ES会将查询发送给每一个分片,并将结果组合起来,对应用透明。
- 副本:为提供吞吐量或者实现高可用,可以使用分片副本,副本是一个分片的Slave,每个分片可以有多个副本,ES可以有许多相同的分片,其中一个被选中更改索引操作,这种分片是主分片。单主分片丢失,集群将副本某一个提升为主分片
- 全文检索:将内容根据词的意义进行分词,让后分别创建索引例如:
- “你们的动力是因为什么事情来的” 可分为:“你们”,“动力”,“什么事情”,“来”等token,当搜索你们,或者动力时候都会讲这个段搜索出来。
ES数据架构主要概念(mySql对比)
- 关系型数据库中数据库(DB)等价es中索引(index)
- 一个数据库下面N张表(table),等价1个索引下N多属性(Type)
- 一个数据库表(table)下的数据由多行,多列组成,等价es中1个Type由多Document和多个Field组成
- 关系型数据库里面,Schema定义了表,每个表的字段,还有表与字段直接的关系,与之对应的ES中:Mapping定义索引下的Type的字段处理规则,即索引如何建立,索引类型,是否保存原始索引JSON文档,是否压缩原始JSON文档,是否需要分词处理,如何进行分词等。
- 数据库中CURD操作等价ES中 增PUT/POST,删Delete,改_update,查GET(标准RESTful)
ELK: elasticsearch+Logstash+kibana
- elasticsearch:后台分布式存储以及全文检索
- logstash:日志加工,日志统计
- kibana:数据可视化展示
- ELK架构为数据分布式存储,可视化查询和日志解析创建了一个功能强大的管理链,三者相互配合完成分布式大数据处理工作。
[新浪ES 如何分析处理32亿条实时日志 ]( <http://dockone.io/article/505 )
特定优势
- 分布式实时文件存储,索引可到某个字段级别检索
- 实时分析的分布式搜索引擎
- 分布式:索引拆分成多个分片,每个分片可有多个副本,集群每个数据节点都可以承载一个或多个分片,并且协调和处理各种操作。
- 负载再平衡和路由大多数情况自动完成
- 可扩展到上百条服务器,处理PB级别结构化或者非结构化数据,也可单机
- 支持插件机制,分词插件,hadoop插件,可视化插件等
倒排索引
- 搜索引擎通常检索的场景是:给的几个关键字,找出包含关键字的文档。怎么快速找到包含某个关键字的文档就成为搜索的关键,倒排索引源于实际应用中需要根据属性的值来查找记录,lucene是基于倒排索引实现的,这种索引表中的每一项都包括一个属性值和具有改属性值的各个记录的地址,由于不是由记录来确认属性值,而是由属性值来确定记录的位置,所以称为倒排索引
正排索引
- 正排索引是以文档的ID为关键字,表中记录文档中每个字的位置信息,查找时候扫描表中每个文档中字的信息直到找出所有包含查询关键字的文档。查询效率相对来说不高。
总结:倒排索引记录了某个关键字在那些文档中,正排索引记录了文档包含了哪些关键字
问题:倒排索引比关系型数据库的b-tree索引快在哪里?
文档
- Elasticsearch是面向文档的,那么搜索和索引数据的最小单元就是文档,在Elasticsearch中文档有以下几个重要的属性:
- 文档是自我包含的,一篇文档包含字段,已经他们的值
- 他可以是层次结构。比如一个JSON个是保存的文档,他某个字段里面还是一个JSON格式,这就是层次结构
- 有灵活的结构,文档不依赖预先定义的模式也就是非schema的形式,也就是在同一个类型下的文档并不一定都包含改类型下的所有字段。
- 尽管我们可以随意的添加数据和忽略数据,但是每个字段的类型在Elasticsearch 中是很重要的:某个字段是字符串,某些是整数等。这一点Elasticsearch 在添加数据的时候,会将字段和类型之间做映射这就是我们说的建立Mapping。这样的映射具体到每个索引的每种类型上面。在Elasticsearch 中也叫作映射类型。
类型
- 类型是文档的逻辑容器,类似表格是行的容器。不同类型中,最好放入不同结构的文档。例如一个类型定义A分组,而另一个类型定义B
- 每个类型中字段的定义就是我们说的Mapping映射。例如name字段可以映射为String。而location中的geolocation可以映射为get_point类型。每种字段都通过不同方式进行处理。例如我们可以在name字段中搜索匹配的关键字,同时根据位置类搜索哪些分组离我的地理位置更近
- 问题在于Elasticsearch 是无模式非schema形式的数据,为什么文档属于一种类型,二每个类型都是类似模式的映射(字段):
- 因为非schema形式是针对文档的,表示 文档是不受模式限制。并不是每个文档都需要包含他所在类型中的所有字段,而是类型映射应该包含他所有文档的所有字段。这就是类型与文档的关系。
- 同样道理,如果一篇新的文档添加后有一个映射不在本类型的字段中,Elasticsearch会自动的将新字段键入映射。为了添加这个字段,Elasticsearch需要先确定这个类型,Elasticsearch猜测类型,例如如果是一个整数7 ,他会将类型建立为整型,所以es的写入性能是不高的,他需要刷新Mapping
- 这种实时刷新Mapping的方式确定在于,在第一次定义7 这个字段是整型后,我对字段进行搜索hello,那么索引会失败,他不是String。对应线上的环境最安全的方式就是先导入数据,建立Mapping后在去搜索
- 类型的Mapping映射只是将文档进行了逻辑划分,从物理上看同一个索引中的文档都是写入磁盘中,而不会考虑他们所在的映射类型。
索引
- 索引是映射类型的容器。一个Elasticsearch索引就像mySql中的数据库级别。是独立的大量文档数据的集合。每个索引存储在磁盘上的同组文件中;索引存储了所有映射的字段。还有一些设置。
- 例如每个索引有一个称为refresh_interval的设置,定义了新进的索引的文档对于搜索的可见的时间间隔。从性能上看,刷新的操作代价是比较大的。这也是为什么更新只能是偶尔进行。默认是一次性导入,而不是逐步的同步,Elasticsearch被称为准实时的,就是因为有这个刷新时间
映射的定义
- 映射的定义就是Mapping建立的一个过程,我会将文档归类,将文档中的每个字段归类到每一个类型中,并且设置改文档的每个字段的查询设置
定义文档字段的核心类型
- 字符串类型
- 字符串是最直接的:如果索引字符,字段就是string类型,也是查询最丰富的的一种类型,因为映射有很多选项设置来分析他
- 解析文本,转变文本,分解为基本元素使得搜索更为相关,这个过程就是分析
- 例如搜索的name字段,当索引到文档的name时候,默认分析器将改文档的内容转为小写,然后将字符分解为单词
- 映射的作用就是在分析过程起作用,可以依据需求来设置映射分析的策略,例如index选项可以设置为:
- anayzed(默认):分析器将所有字符转小写,并且将字符串分解为单词
- not_analyzed:分析过程被略过,整个字段需要全量匹配
- no:索引略过该字段。
- 数值类型
- 包括byte,short, int, long数值型 float, double浮点型
- 这些对于的java原始数据类型,显然字段选择会影响索引的大小,在存储数据的索引中,字符占用内存越大,数据量也就越大,最好选择合适的数据类型
- 日期类型
分析数据
- 分析(analysis)是在文档被发送并加入倒排索引之前,Elasticsearch在其数据上进行的一个处理。
- 数据添加到索引前做的事情:
- 字符过滤: 使用字符过滤器转变字符
- 文本切分成词组: 将文本切分成单个的单词
- 分词过滤: 使用分词过滤转变每个分词
- 分词索引: 将这些分词存储到索引中。
- 整个流程如下图:
字符过滤
- Elasticsearch运行字符过滤器,将特定字符列转换为其他字符序列。可以将HTML从文本中剥离,或者将任意字符转化为其他字符(例如“ I LOVE u 2” 转为 “i love you too”)如上我们设置特殊的将&符合转为 and
切分为分词
- 文本需要被分割成可以操作的片段。Lucene自己不会对大块的字符串数据进行操作,他直接处理被称为分词(token)的数据。分词是从文本片段生成的,可以产生任意数量,
分词过滤器
- 被分词后得到的token,Elasticsearch会将每个分词运用分词过滤器,他可以将一个分词作为输入,然后更具需要进行修改,添加,删除。最有用的和常用的分词过滤器是小写分词过滤器将输入分词转为小写,这样我们早修改noSql的时候也可以同时发现NoSql的聚合。
分词索引
- 当温度经过0~n个分词过滤器后,将发送到lucene进行文档索引。
- 以上所有的不同组件部分组成了一个分析器(analyzer),Elasticsearch提供了很多这种分析器可以直接使用而不用构建自己的分析器
内置分析器
- 一个分析器包括一个可选的字符过滤器,一个单个分词器,0个或者多个分词过滤器
- 如下有几种分析器,每种功能都不同
- 标准分析器:文本的默认分析器包括 标准分析器,标准分词过滤器,小写转换分词过滤器和停用分词过滤器
- 简单分析器:只永小写转换分词器
- 空白分析器:什么都不做,值更具空包将文本进行拆分
- 停用词分析器:在分词流中过滤停用词
- 关键词分析器:将整个字段当成单独一个分词
- 模式分析器:
- 语言和多语言分析器:Elasticsearch能直接使用的特点语言分析器包括汉语等
- 雪球分析器
分词器
-
以上说过,分词器将文本分解成小块token,Elasticsearch 内部也包含了一些内置的分词器
- 标准分词器:基于语法的分词器,针对英语等欧洲语法
'I hava , potatoes.' 切分后 I,have, potatoes
- 关键词分词器:简单的将文本作为单个的单词提供给分词过滤器,但我们不想在拆分的时候可以用
'Hi, there' 切分后 Hi, there
- 字母分词器:更具妃子们的符号,将文本切分为分词,去掉符号等
'Hi, there' 切分后 hi 与 there
- 小写分词器:结合了常规字母分词器和小写分词过滤器,功能结合提升性能
'Hi, there' 切分后 Hi, 与 there
- 空白分词器:通过空白分割不同分词,空白包括:空格,制表符,换行符
- 模式分词器:
- UAX URL 电子邮件分词器
- 路劲层次分词器
分词过滤器
- Elasticsearch中有很多分词过滤器,如下图三个简单的分词过滤
- 标准分词过滤器:什么都没做
- 小写分词过滤器:将任何进过的分词转小写
- 长度分词过滤器:将长度不符合配置范围内的单词过滤,可设置
- 停用词分词过滤器:将停用词从分词中删除,针对英文的过滤
- 截断分词过滤器,修剪分词过滤器和限制分词数量过滤器:
- 截断分词过滤器:运行通过盯着配置中length参数,截断超过一定长度分词,默认配置是阶段多余10个字符的部分
- 修剪分词过滤器:删除一个分词中所有空包
- 限制分词数量分词过滤器:现在某个字段可能包含分词的最大数量,比如文本太长,限制8 ,那么就只会有8个分词被索引
- 颠倒分词过滤器:允许一个分词流并且颠倒每个单词
- 唯一分词过滤器:
- ASCII折叠分词过滤器
- 同义词分词过滤器:在分词流中的同样位移处,用关键词的同义词取代原始词
Mapping构建总结
- ElasticSearch 的查询是基于 luncene实现的,但是luncene只是一个检索库,他能处理的数据单元并非是整个文档类型,lucene是基于倒排索引实现的,这种索引表的结构特点在于,表中的每个属性都对应各个记录的具体文档位置,这样可以直接通过查询属性key来找到对应的文档集合。
- ElasticSearch对数据的处理就是要将普通的文档 处理成 (属性-- 结果地址)这种数据字典,同时对字段进行一些特殊设置这就是Mapping建立过程
- 在文档添加的时候,将结构相似的文档归为同一个类型下,该类型包含了所有文档中的每个属性
- 在添加到文档之前,文档需要经过ElasticSearch分析器的处理,它包括字符过滤器,分词器,分词过滤器,分别是字符过滤,分词,特定功能呢过滤的能力,每个功能都内置了不同功能的插件,可以依据业务的需要选择,也可以选择外部插件,例如中文IK分词器就是在分词阶段起作用。最后将得到的分词存储到索引中。如下图示意流程
- 每个索引可能有多个分类,而每个分类下是包含本类别文档的所有分词信息,这样就得到了如下模式的一个数据结构
倒排索引性能总结
- 在为属性(field)构建倒排索引后,此时,本类别中包含了所有文档中所有字段的一个 分词(term) 文档id对应关系的字典信息
- 通过倒排索引,我们可以迅速找到符合添加的文档,例如peace在文档 2,3,4 中。
- 当我们进行Elasticsearch查询,为了能快速找到某个term,ElasticSearch 将类型中所有的term进行排序,然后通过二分法查找term,时间复杂度能达到 logN的查找效率,就像通过字典查找一样,这就是Term Dictionary
- 同时参照 B-Tree通过减少磁盘寻道次数来提高查询性能,Elasticsearch也是采用同样的思路,直接通过内存查找term,将term Dictionary这个构建的Mapping存放在内存中。但是如果term太多,term dictionary也会很大,放内存不现实,于是有了Term Index,就像字典里的索引页一样,A开头的有哪些term,分别在哪页,可以理解term index是一颗树如下图:
-
如上图中数据结构是字典树,同时也叫tire树, 有如下结构特性:
- 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
- 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
- 每个节点的所有子节点包含的字符都不相同。
-
如上第二点中每个节点都只包含一个字符,如图中te 是结合了第一个节点t, 和本节点e,得到的一个结果是te,本节点此时值存储了一个字符e
-
字典树平均时间复杂度:复杂度为O(n*len),实际查询的复杂度也只是O(len)。(Trie树的平均高度h为len,所以Trie树的查询复杂度为O(h)=O(len)
-
树节点存储的是term的前缀信息,通过前缀查询关键字在term Dictionary中的偏移量,然后在遍历对应的Term Dictionary 对应的这段数据找到具体的term, 存储的是Term前缀 与 Term Dictionary 的block之间的映射关系
-
在此基础上在对内存中的Term index进行数据压缩,这样的话用时间换空间,的方式减少内存的占用,这样就可以完全在内存中找到对应的文档id,最后去磁盘读取对应的文档信息。磁盘随机读的次数
-
额外的知识:
- MySql Innodb存储引擎在1.2版本后也支持了全文检索,通MyISam存储引擎一样,在创建全文检索所有后,mysql会将对应字段进行分词
- 分词后的分词,文档id字典信息存储在六张表中
- 同样的,MySql全文检索为了优化查询,将全文检索索引(也就是字典)缓存在内存中,也同样的是通过内存区查询
- MySql此时也同样用来前缀存储的方法去减少内存的占用,但是这里MySql并不是和es一样用的term index的字典表,有MySql用的红黑树来存储term directionary
- 并且MySql还做了数据压缩处理,在红黑树中得到的前缀是sab,找到对应字段offset后的所有对应的数据存储的方式是将sab省略的后半部分,以这种方式来减少磁盘的占用
- MySql 还对全文索引对应的字段的insert, delete操作进行了优化,因为我们真正查询的时候是用的字典,并不是全文检索本文
- 当insert的时候,MySql对全文索引字段进行分词,此时并不会直接将新的字段数据更新到字典表,而是直接更新全文检索索引缓存,只有在正在用到索引缓存进行数据查询的时候,才会真正更新到对应的字典表中
- MySql对删除有同样的处理,当我们删除一个文档时候,MySql会将文档id添加到一张删除记录表中,并且更新对应的索引缓存,还是在查询的时候,更新字典表。
- 红黑树查询平均时间复杂度是O(logn)
-
索引失效与解决方案
2021-03-01 09:57:33文章目录可能导致索引失效的场景1. 索引列不独立. 独立是指: 列不能是表达式的一部分, 也不能是函数的参数解决方案:2. 使用了左模糊3. 使用or查询的部分字段没有索引解决方案:4. 字符串条件为使用 ' ' 引起来解决...文章目录
可能导致索引失效的场景
1. 索引列不独立. 独立是指: 列不能是表达式的一部分, 也不能是函数的参数
例如:
where条件的左侧有计算explain select * from employees where emp_no + 1 = 10003;
此时的 explain 为 all
解决方案:
将 条件改到where条件的右面 :
explain select * from exployee where emp_no = 10003 -1;
此时的explain 为 const
2. 使用了左模糊
例如:
explain * from employees where first_name like '%Geo%'
解决方案:
尽量避免使用左连接, 如果避免不了, 可以考虑使用搜索引擎去解决;explain * from employees where first_name like 'Geo%'
3. 使用or查询的部分字段没有索引
例如: first_name 有索引, last_name 没有索引, 则如下语句不能使用索引
explain select * from employees where first_name = 'Georgi' or last_name = 'Georgi';
解决方案:
额外添加 or 条件的索引, 这时候数据库会默认的将两个索引合并, 避免了全表扫描.
4. 字符串条件为使用 ’ ’ 引起来
例: 字符串条件未使用 ’ ’ 引起来 (dept_no 为字符串)
explain select * from dept_emp where dept_no = 3;
结果type 为 all
解决方案: 添加 ’ ’ , 规范的编写 sql
5. 不符合最左前缀原则的查询
解决方案:
调整索引的顺序, 变成index(first_name, last_name)
6. 索引字段建议添加 NOT NULL 约束
单列索引无法存储null值, 复合索引无法存储全为null的值
查询时, 采用 is null 条件时, 不能利用到索引, 只能全表扫描
mysql 官方建议尽量把字段定义为 NOT NULL解决方案:
把索引字段设置成 NOT NULL, 甚至可以把所有字段都设置为 NOT NULL, 并且为字段设置默认值
7. 隐式转换导致索引失效
在创建表的时候要尽量规范: 比如使用int 或者 bigint
8. 索引失效导致行锁升级为表锁
我们之前对session-1和session-2都进行了关闭自动提交.
set autocomit=0; 关闭自动提交
索引类型(常用的6种):
索引失效则为 all (全表扫描)
覆盖索引: 从索引中直接获取查询结果,要使用覆盖索引需要注意select查询列中包含在索引列中;where条件包含索引列或者复合索引的前导列;查询结果的字段长度尽可能少。1. all
“全表扫描”,通常意味着你的sql语句处于一种最原生的状态,有很大的优化空间, 我们都要避免这样类型的查找,除非你不得不这样做。
2. index
这种连接类型只是另外一种形式的全表扫描,只不过它的扫描顺序是按照索引的顺序。这种扫描根据索引然后回表取数据,和all相比,他们都是取得了全表的数据,而且index要先读索引而且要回表随机取数据.
3. range
range指的是有范围的索引扫描,相对于index的全索引扫描,它有范围限制,因此要优于index。关于range比较容易理解,需要记住的是
出现了range,则一定是基于索引的
。同时除了显而易见的between,and以及’>’,’<'外,in和or也是索引范围扫描。4. ref
出现该连接类型的条件是: 查找条件列使用了索引而且不为主键和unique。
其实,意思就是虽然使用了索引,但该索引列的值并不唯一,会有重复。这样即使使用索引快速查找到了第一条数据,仍然不能停止,要进行目标值附近的小范围扫描。
但它的好处是它并不需要扫描全表,因为索引是有序的,即便有重复值,也是在一个非常小的范围内扫描。5. ref_eq
ref_eq 与 ref相比牛的地方是,它知道这种类型的查找结果集只有一个?什么情况下结果集只有一个呢!那便是使用了主键或者唯一性索引进行查找的情况,比如根据学号查找某一学校的一名同学,在没有查找前我们就知道结果一定只有一个,所以当我们首次查找到这个学号,便立即停止了查询。这种连接类型每次都进行着精确查询,无需过多的扫描,因此查找效率更高,当然列的唯一性是需要根据实际情况决定的。
6. const
通常情况下,如果将一个主键放置到where后面作为条件查询,mysql优化器就能把这次查询优化转化为一个常量。至于如何转化以及何时转化,这个取决于优化器。
-
【kafka原理】kafka Log存储解析以及索引机制
2020-10-26 19:26:19会定时更新 follower被选为leader时会根据这个确定哪些消息可用 参考文档 kafka官方文档 Kafka的Log存储解析 Kafka-工作流程,文件存储机制,索引机制,如何通过offset找到对应的消息 Broker配置文件详解 日常运维...本文设置到的配置项有
名称 描述 类型 默认 num.partitions topic的默认分区数 int 1 log.dirs 保存日志数据的目录。如果未设置,则使用log.dir中的值 string /tmp/kafka-logs offsets.topic.replication.factor offset topic复制因子(ps:就是备份数,设置的越高来确保可用性)。为了确保offset topic有效的复制因子,第一次请求offset topic时,活的broker的数量必须最少最少是配置的复制因子数。 如果不是,offset topic将创建失败或获取最小的复制因子(活着的broker,复制因子的配置) short 3 log.index.interval.bytes 添加一个条目到offset的间隔 int 4096 首先启动kafka集群,集群中有三台Broker; 设置3个分区,3个副本;
发送topic消息
启动之后
kafka-client
发送一个topic为消息szz-test-topic
的消息public static void main(String[] args) { Properties props = new Properties(); props.put("bootstrap.servers", "xxx1:9092,xxx2:9092,xxx3:9092"); props.put("acks", "all"); props.put("retries", 0); props.put("batch.size", 16384); props.put("linger.ms", 1); props.put("buffer.memory", 33554432); props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); Producer<String, String> producer = new KafkaProducer<>(props); for(int i = 0; i < 5; i++){ producer.send(new ProducerRecord<String, String>("szz-test-topic", Integer.toString(i), Integer.toString(i))); } producer.close(); }
发送了之后可以去
log.dirs
路径下看看
这里的3个文件夹分别代表的是3个分区; 那是因为我们配置了这个topic的分区数num.partitions=3
; 和备份数offsets.topic.replication.factor=3
; 这3个文件夹中的3个分区有Leader
有Fllower
; 那么我们怎么知道谁是谁的Leader呢?查看topic的分区和副本
bin/kafka-topics.sh --describe --topic szz-test-topic --zookeeper localhost:2181
可以看到查询出来显示
分区Partition-0在broker.id=0
中,其余的是副本Replicas
2,1
分区Partition-1在broker.id=1
中,其余的是副本Replicas
0,2
…或者也可以通过zk来 查看
leader
在哪个broker上get /brokers/topics/src-test-topic/partitions/0/state
[zk: localhost:2181(CONNECTED) 0] get /brokers/topics/szz-test-topic/partitions/0/state {"controller_epoch":5,"leader":0,"version":1,"leader_epoch":0,"isr":[0,1,2]} cZxid = 0x1001995bf
分区文件都有啥
进入文件夹看到如下文件:
名称 描述 类型 默认 log.segment.bytes 单个日志文件的最大大小 int 1073741824 我们试试多发送一些消息,看它会不会生成新的
segment
public static void main(String[] args) { Properties props = new Properties(); props.put("bootstrap.servers", "xxx1:9092,xxx2:9092,xxx3:9092"); props.put("acks", "all"); props.put("retries", 0); props.put("batch.size", 163840); props.put("linger.ms", 10); props.put("buffer.memory", 33554432); props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); Producer<String, String> producer = new KafkaProducer<>(props); for(int i = 0; i < 1200; i++){ //将一个消息设置大一点 byte[] log = new byte[904800]; String slog = new String(log); producer.send(new ProducerRecord<String, String>("szz-test-topic",0, Integer.toString(i), slog)); } producer.close(); }
从图中可以看到第一个segment文件
00000000000000000000.log
快要满log.segment.bytes
的时候就开始创建了00000000000000005084.log
了;
并且.log
和.index
、.timeindex
文件是一起出现的; 并且名称是以文件第一个offset命名的- .log存储消息文件
- .index存储消息的索引
- .timeIndex,时间索引文件,通过时间戳做索引
消息文件
上面的几个文件我们来使用kafka自带工具
bin/kafka-run-class.sh
来读取一下都是些啥
bin/kafka-run-class.sh kafka.tools.DumpLogSegments --files 00000000000000000000.log
最后一行:baseoffset:5083 position: 1072592768 CreateTime: 1603703296169
.index 消息索引
bin/kafka-run-class.sh kafka.tools.DumpLogSegments --files 00000000000000000000.index
最后一行:offset:5083 position:1072592768
.timeindex 时间索引文件
bin/kafka-run-class.sh kafka.tools.DumpLogSegments --files 00000000000000000000.timeindex
最后一行:timestamp: 1603703296169 offset: 5083
Kafka如何查找指定offset的Message的
找了个博主的图 @lizhitao
比如:要查找绝对offset为7的Message:- 首先是用二分查找确定它是在哪个LogSegment中,自然是在第一个Segment中。
- 打开这个Segment的index文件,也是用二分查找找到offset小于或者等于指定offset的索引条目中最大的那个offset。自然offset为6的那个索引是我们要找的,通过索引文件我们知道offset为6的Message在数据文件中的位置为9807。
- 打开数据文件,从位置为9807的那个地方开始顺序扫描直到找到offset为7的那条Message。
Kafka 中的索引文件,以
稀疏索引(sparse index)
的方式构造消息的索引,它并不保证每个消息在索引文件中都有对应的索引项。每当写入一定量(由 broker 端参数log.index.interval.bytes
指定,默认值为 4096,即 4KB)的消息时,偏移量索引文件 和 时间戳索引文件 分别增加一个偏移量索引项和时间戳索引项,增大或减小log.index.interval.bytes
的值,对应地可以缩小或增加索引项的密度。稀疏索引通过
MappedByteBuffer
将索引文件映射到内存中,以加快索引的查询速度。leader-epoch-checkpoint
leader-epoch-checkpoint 中保存了每一任leader开始写入消息时的offset; 会定时更新
follower被选为leader时会根据这个确定哪些消息可用
参考文档
Kafka-工作流程,文件存储机制,索引机制,如何通过offset找到对应的消息
日常运维、问题排查=> 滴滴开源LogiKM一站式Kafka监控与管控平台
-
cJSON文档解析
2018-10-15 15:34:12cJSON文档解析 cJSON是一个轻量级且易于扩展的JSON解析开源库。 github地址为:https://github.com/DaveGamble/cJSON 安装与使用 源码安装:将cJSON.c与cJSON.h这两个文件复制入自己的工程项目中,通过#... -
SpringBoot整合Elasticsearch之索引,映射,文档,搜索的基本操作案例分析
2022-02-04 09:42:36索引,映射,文档,DSL增删改查一)环境准备1. ES版本:7.12.12. SpringBoot版本:2.5.8二)ES的基本介绍1. Elasticsearch 是什么2. Eelasticsearch的作用3. Elasticsearch,Solr和Lucene三者之间的关系4. Elastic... -
ArrayList源码万字解析!透彻易懂!
2020-05-20 20:22:05本文我们结合源码用通俗易懂的语言来解析ArrayList,尽量给每一行源码都写上注释,给每一个功能加上总结,助你进大厂一臂之力 -
ES5.6.4源码解析--批量索引bulk
2018-08-28 20:00:15ES的批量索引操作,可以把多条索引请求合成一次请求,每个请求可以指定不同的索引。当往ES中索引大量数据的时候,使用批量索引能够大大增加索引的数据。接下来让我们通过阅读批量索引的源码来揭开其神秘的面纱。 ... -
cassandra 3.x官方文档(2)---架构解析
2016-11-25 13:03:38写在前面 cassandra3.x官方文档的非官方翻译。翻译内容水平全依赖本人英文水平和对cassandra的理解。所以强烈建议阅读英文版cassandra 3.x 官方文档。此文档一半是翻译,一半是个人对cassandra的认知。尽量将我的... -
精易模块源码V8.0.5
2022-05-27 08:38:082、修复“网页_取IP地址”,返回的响应文本存在换行可能导致JSON解析失败的问题;感谢【@寒潮 】反馈问题;。3、修复“进程_取命令行”,句柄释放的问题;。4、修复“ADSL拨号类 - 拨号_cmd”、“ADSL拨号类 - 断开_... -
当年,学姐把这份Java总结给我,让我在22k的校招王者局乱杀
2021-04-22 08:41:36可以说,学姐给我的这份文档真的把我的知识查漏补缺,面试问到了好多,值得收藏。 -
使用kibana管理索引
2021-01-16 22:18:53curl是利用URL语法在命令行方式下工作的开源文件传输工具,使用curl可以简单实现常见的get/post请求。简单的认为是可以在命令行下面访问url的一个工具。在centos的默认库里面是有curl工具的,如果没有请yum安装即可... -
ES倒排索引与分词详解
2018-10-16 16:55:51正排索引:文档id到单词的关联关系 倒排索引:单词到文档id的关联关系 示例: 对以下三个文档去除停用词后构造倒排索引 image 倒排索引-查询过程 查询包含“搜索引擎”的文档 通过倒排索引获得“搜索引擎... -
SolrCloud索引与搜索过程解析
2018-04-18 16:30:14更强大的是,它还能自动的在其它机器上帮你把失败机器上的索引Replication重建并投入使用。 近实时搜索: 立即推送式的replication(也支持慢推送)。可以在秒内检索到新加入索引。 查询时自动负载均衡: SolrCloud... -
【Elasticsearch索引恢复流程(上)】
2019-05-29 10:03:25恢复Lucene文件,以及在节点间复制索引数据 从Lucene读取最后一次提交的分段信息,获取版本号,更新当前索引版本 VERIFY_INDEX 验证索引是否损坏 参数可配,默认配置为不执行验证索引,进入最重要的... -
PLY文档翻译——利用Python进行词法和语法分析
2019-07-29 21:49:55本文档提供了使用PLY进行词法分析和解析的概述,考虑到解析的内在复杂性,我强烈建议您在使用PLY进行大型开发项目之前阅读(或至少略读)整个文档。 2. Introduction PLY是流行的编译器构造工具lex和yacc的纯python... -
Elasticsearch 分片管理解析
2019-06-12 11:25:09一个 shard 本质上就是一个 Lucene 索引,也是 Elasticsearch 分布式化 Lucene 的关键抽象,是 Elasticsearch 管理 Lucene 文件的最小单位。所以,Elasticsearch 提供了大量的接口,可以对集群内的 shard 进行管理。... -
Elasticsearch索引的基本操作(6)-索引设置
2019-06-20 15:32:321、索引设置的查看 查看索引的设置通过_settings API,使用GET方法操作。 1.1、查看单个索引的设置 查看索引new_index的设置,操作如下: GET /new_index/_settings 响应如下: { "new_index... -
MySQL索引的数据结构以及算法原理
2018-04-19 22:13:28写在前面的话 在编程领域有一句人尽皆知的法则“程序 = 数据结构 + 算法”,我个人是不太赞同这句话(因为我觉得程序不仅仅是数据结构加算法),但是在日常的学习和工作中我确认深深感受到数据结构和算法的重要性,... -
Mysql数据库索引原理及算法原理
2019-03-07 18:01:23最近在网上看到了一篇关于mysql数据库索引的好文章,认真看完之后肯定受益匪浅,(虽说有的地方我不太理解)转来供大家学习交流。 另外:Ctrl C+V 好累啊,有没有快捷转载方法? 摘要 本文以MySQL数据库为研究... -
mysql索引调优
2021-03-12 14:34:09在该层,服务器会解析查询并创建相应的内部解析树,并对其完成相应的优化如确定查询表的顺序,是否利用索引等,最后生成相应的执行操作。如果是select语句,服务器还会查询内部的缓存。如果缓存空间足够大,这样在... -
网页解析
2020-12-04 08:49:04在网络爬虫的系统框架中,主过程由控制,解析,资源库三部分组成。解析是负责网络爬虫的一个部分,其负责的工作主要有:下载网页的功能,对网页的文本进行处理,如过滤功能,抽取特殊HTML标签的功能,分析数据功能。... -
Springboot入门到精通(超详细文档)
2021-06-24 15:01:23我们知道,从 2002 年开始,Spring 一直在飞速的发展,如今已经成为了在Java EE(Java Enterprise Edition)开发中真正意义上的标准,但是随着技术的发展,Java EE使用 Spring 逐渐变得笨重起来,大量的 XML 文件... -
公众号600篇文章分类和索引
2020-02-27 07:30:00索引重建失败的解决 SELECT和DELETE执行计划的不同选择 一个DATE数据类型的检索 DELETE选错执行计划的困境 《一次Oracle bug的故障排查过程思考》的问题重现解决 应用执行慢的问题排查路径 数据库连接池配置参考 一... -
【Elasticsearch入门】ElasticSearch索引
2019-06-06 19:21:59索引是具有相同结构的文档集合。在 Elasticsearch中索引是个非常重要的内容,对Elasticsearch的大部分操作都是基于索引来完成的。 1、索引管理 1.1、创建索引 创建索引的时候可以通过修改 number_of_shards和 ... -
【ES】RestHighLevelClient自动创建按月索引如何实现(二)
2021-07-02 16:43:45记录对于es处于java中的相关业务需要做按月索引的实现 https://blog.csdn.net/ssdlleave/article/details/107846094?spm=1001.2014.3001.5501 定义es gis-location模版kibana添加 POST _template/template-gis-... -
阿里巴巴开发手册解析个人笔记(五)Mysql规约(二)索引规约
2019-01-07 02:14:09文章目录(二)索引规约索引口诀1. 【强制】业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引。2. 【强制】超过三个表禁止 join。...3. 【强制】在 varchar 字段上建立索引时,必须指定索引... -
Spring官方文档(中文版!!!)
2020-03-18 19:10:43本文档是对spring官方文档的解读,原文档参见Spring官方文档 ,本人只是翻译和整理,由于水平有限,部分解读可能不正确,欢迎提出更好的意见和建议或者与我一起完成本次挑战!网页版移步我的临时网页 Git传送门 1 ...