精华内容
下载资源
问答
  • mysql索引详解

    万次阅读 多人点赞 2021-07-07 21:40:09
    分别为:表定义文件、数据文件、索引文件。第一个文件的名字以表的名字开始,扩展名指出文件类型。.frm文件存储表定义。数据文件的扩展名为.MYD (MYData)。索引文件的扩展名是.MYI (MYIndex)。 InnoDB:所有的表都...

    🍅 Java学习路线:搬砖工逆袭Java架构师

    🍅 简介:Java领域优质创作者🏆、CSDN哪吒公众号作者✌ 、Java架构师奋斗者💪

    🍅 扫描主页左侧二维码,加入群聊,一起学习、一起进步 

    🍅 欢迎点赞 👍 收藏 ⭐留言 📝  

    一、MySQL三层逻辑架构

    MySQL的存储引擎架构将查询处理与数据的存储/提取相分离。下面是MySQL的逻辑架构图:

    1、第一层负责连接管理、授权认证、安全等等。

    每个客户端的连接都对应着服务器上的一个线程。服务器上维护了一个线程池,避免为每个连接都创建销毁一个线程。当客户端连接到MySQL服务器时,服务器对其进行认证。可以通过用户名和密码的方式进行认证,也可以通过SSL证书进行认证。登录认证通过后,服务器还会验证该客户端是否有执行某个查询的权限。

    2、第二层负责解析查询

    编译SQL,并对其进行优化(如调整表的读取顺序,选择合适的索引等)。对于SELECT语句,在解析查询前,服务器会先检查查询缓存,如果能在其中找到对应的查询结果,则无需再进行查询解析、优化等过程,直接返回查询结果。存储过程、触发器、视图等都在这一层实现。

    3、第三层是存储引擎

    存储引擎负责在MySQL中存储数据、提取数据、开启一个事务等等。存储引擎通过API与上层进行通信,这些API屏蔽了不同存储引擎之间的差异,使得这些差异对上层查询过程透明。存储引擎不会去解析SQL。

    二、对比InnoDB与MyISAM

    1、 存储结构

    MyISAM:每个MyISAM在磁盘上存储成三个文件。分别为:表定义文件、数据文件、索引文件。第一个文件的名字以表的名字开始,扩展名指出文件类型。.frm文件存储表定义。数据文件的扩展名为.MYD (MYData)。索引文件的扩展名是.MYI (MYIndex)。

    InnoDB:所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。

    2、 存储空间

    MyISAM: MyISAM支持支持三种不同的存储格式:静态表(默认,但是注意数据末尾不能有空格,会被去掉)、动态表、压缩表。当表在创建之后并导入数据之后,不会再进行修改操作,可以使用压缩表,极大的减少磁盘的空间占用。

    InnoDB: 需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。

    3、 可移植性、备份及恢复

    MyISAM:数据是以文件的形式存储,所以在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进行操作。

    InnoDB:免费的方案可以是拷贝数据文件、备份 binlog,或者用 mysqldump,在数据量达到几十G的时候就相对痛苦了。

    4、 事务支持

    MyISAM:强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但是不提供事务支持。

    InnoDB:提供事务支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。

    5、 AUTO_INCREMENT

    MyISAM:可以和其他字段一起建立联合索引。引擎的自动增长列必须是索引,如果是组合索引,自动增长可以不是第一列,他可以根据前面几列进行排序后递增。

    InnoDB:InnoDB中必须包含只有该字段的索引。引擎的自动增长列必须是索引,如果是组合索引也必须是组合索引的第一列。

    6、 表锁差异

    MyISAM: 只支持表级锁,用户在操作myisam表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。

    InnoDB: 支持事务和行级锁,是innodb的最大特色。行锁大幅度提高了多用户并发操作的新能。但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。

    7、 全文索引

    MyISAM:支持 FULLTEXT类型的全文索引

    InnoDB:不支持FULLTEXT类型的全文索引,但是innodb可以使用sphinx插件支持全文索引,并且效果更好。

    8、表主键

    MyISAM:允许没有任何索引和主键的表存在,索引都是保存行的地址。

    InnoDB:如果没有设定主键或者非空唯一索引,就会自动生成一个6字节的主键(用户不可见),数据是主索引的一部分,附加索引保存的是主索引的值。

    9、表的具体行数

    MyISAM: 保存有表的总行数,如果select count() from table;会直接取出出该值。

    InnoDB: 没有保存表的总行数,如果使用select count(*) from table;就会遍历整个表,消耗相当大,但是在加了wehre条件后,myisam和innodb处理的方式都一样。

    10、CRUD操作

    MyISAM:如果执行大量的SELECT,MyISAM是更好的选择。

    InnoDB:如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表。

    11、 外键

    MyISAM:不支持

    InnoDB:支持

    三、sql优化简介

    1、什么情况下进行sql优化

    性能低、执行时间太长、等待时间太长、连接查询、索引失效。

    2、sql语句执行过程

    (1)编写过程

    select distinct ... from ... join ... on ... where ... group by ... having ... order by ... limit ...

    (2)解析过程

    from ... on ... join ... where ... group by ... having ... select distinct ... order by ... limit ...

    3、sql优化就是优化索引

    索引相当于书的目录。

    索引的数据结构是B+树。

    四、索引

    1、索引的优势

    (1)提高查询效率(降低IO使用率)

    (2)降低CPU使用率

    比如查询order by age desc,因为B+索引树本身就是排好序的,所以再查询如果触发索引,就不用再重新查询了。

    2、索引的弊端

    (1)索引本身很大,可以存放在内存或硬盘上,通常存储在硬盘上。

    (2)索引不是所有情况都使用,比如①少量数据②频繁变化的字段③很少使用的字段

    (3)索引会降低增删改的效率

    3、索引的分类

    (1)单值索引

    (2)唯一索引

    (3)联合索引

    (4)主键索引

    备注:唯一索引和主键索引唯一的区别:主键索引不能为null

    4、创建索引

    alter table user add INDEX `user_index_username_password` (`username`,`password`)

    5、MySQL索引原理 -> B+树

    MySQL索引的底层数据结构是B+树

    B+Tree是在B-Tree基础上的一种优化,使其更适合实现外存储索引结构,InnoDB存储引擎就是用B+Tree实现其索引结构。

    B-Tree结构图中每个节点中不仅包含数据的key值,还有data值。而每一个页的存储空间是有限的,如果data数据较大时将会导致每个节点(即一个页)能存储的key的数量很小,当存储的数据量很大时同样会导致B-Tree的深度较大,增大查询时的磁盘I/O次数,进而影响查询效率。在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+Tree的高度。

    B+Tree相对于B-Tree有几点不同:

    非叶子节点只存储键值信息。
    所有叶子节点之间都有一个链指针。
    数据记录都存放在叶子节点中。
    将上一节中的B-Tree优化,由于B+Tree的非叶子节点只存储键值信息,假设每个磁盘块能存储4个键值及指针信息,则变成B+Tree后其结构如下图所示:

    通常在B+Tree上有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点,而且所有叶子节点(即数据节点)之间是一种链式环结构。因此可以对B+Tree进行两种查找运算:一种是对于主键的范围查找和分页查找,另一种是从根节点开始,进行随机查找。

    可能上面例子中只有22条数据记录,看不出B+Tree的优点,下面做一个推算:

    InnoDB存储引擎中页的大小为16KB,一般表的主键类型为INT(占用4个字节)或BIGINT(占用8个字节),指针类型也一般为4或8个字节,也就是说一个页(B+Tree中的一个节点)中大概存储16KB/(8B+8B)=1K个键值(因为是估值,为方便计算,这里的K取值为〖10〗^3)。也就是说一个深度为3的B+Tree索引可以维护10^3 * 10^3 * 10^3 = 10亿 条记录。

    实际情况中每个节点可能不能填充满,因此在数据库中,B+Tree的高度一般都在2~4层。MySQL的InnoDB存储引擎在设计时是将根节点常驻内存的,也就是说查找某一键值的行记录时最多只需要1~3次磁盘I/O操作。

    数据库中的B+Tree索引可以分为聚集索引(clustered index)和辅助索引(secondary index)。上面的B+Tree示例图在数据库中的实现即为聚集索引,聚集索引的B+Tree中的叶子节点存放的是整张表的行记录数据。辅助索引与聚集索引的区别在于辅助索引的叶子节点并不包含行记录的全部数据,而是存储相应行数据的聚集索引键,即主键。当通过辅助索引来查询数据时,InnoDB存储引擎会遍历辅助索引找到主键,然后再通过主键在聚集索引中找到完整的行记录数据。

    五、如何触发联合索引

    1、对user表建立联合索引username、password

    2、触发联合索引

    (1)使用联合索引的全部索引键可触发联合索引

    (2)使用联合索引的全部索引键,但是用or连接的,不可触发联合索引

    (3)单独使用联合索引的左边第一个字段时,可触发联合索引

    (4)单独使用联合索引的其它字段时,不可触发联合索引

    六、分析sql的执行计划---explain

    explain可以模拟sql优化执行sql语句。

    1、explan使用简介

    (1)用户表

    (2)部门表

    (3)未触发索引

    (4)触发索引

    (5)结果分析

    explain中第一行出现的表是驱动表。

    1. 指定了联接条件时,满足查询条件的记录行数少的表为[驱动表]
    2. 未指定联接条件时,行数少的表为[驱动表]

    对驱动表直接进行排序就会触发索引,对非驱动表进行排序不会触发索引。

    2、explain查询结果简介

    (1)id:SELECT识别符。这是SELECT的查询序列号。

    (2)select_type:SELECT类型:

    1. SIMPLE: 简单SELECT(不使用UNION或子查询)
    2. PRIMARY: 最外面的SELECT
    3. UNION:UNION中的第二个或后面的SELECT语句
    4. DEPENDENT UNION:UNION中的第二个或后面的SELECT语句,取决于外面的查询
    5. UNION RESULT:UNION的结果
    6. SUBQUERY:子查询中的第一个SELECT
    7. DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询
    8. DERIVED:导出表的SELECT(FROM子句的子查询)

    (3)table:表名

    (4)type:联接类型

    1. system:表仅有一行(=系统表)。这是const联接类型的一个特例。
    2. const:表最多有一个匹配行,它将在查询开始时被读取。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。const用于用常数值比较PRIMARY KEY或UNIQUE索引的所有部分时。
    3. eq_ref:对于每个来自于前面的表的行组合,从该表中读取一行。这可能是最好的联接类型,除了const类型。它用在一个索引的所有部分被联接使用并且索引是UNIQUE或PRIMARY KEY。eq_ref可以用于使用= 操作符比较的带索引的列。比较值可以为常量或一个使用在该表前面所读取的表的列的表达式。
    4. ref:对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。如果联接只使用键的最左边的前缀,或如果键不是UNIQUE或PRIMARY KEY(换句话说,如果联接不能基于关键字选择单个行的话),则使用ref。如果使用的键仅仅匹配少量行,该联接类型是不错的。ref可以用于使用=或<=>操作符的带索引的列。
    5. ref_or_null:该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。在解决子查询中经常使用该联接类型的优化。
    6. index_merge:该联接类型表示使用了索引合并优化方法。在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素。
    7. unique_subquery:该类型替换了下面形式的IN子查询的ref:value IN (SELECT primary_key FROMsingle_table WHERE some_expr);unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。
    8. index_subquery:该联接类型类似于unique_subquery。可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引:value IN (SELECT key_column FROM single_table WHERE some_expr)
    9. range:只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。key_len包含所使用索引的最长关键元素。在该类型中ref列为NULL。当使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用range
    10. index:该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。
    11. all:对于每个来自于先前的表的行组合,进行完整的表扫描。如果表是第一个没标记const的表,这通常不好,并且通常在它情况下很差。通常可以增加更多的索引而不要使用ALL,使得行能基于前面的表中的常数值或列值被检索出。

    (5)possible_keys:possible_keys列指出MySQL能使用哪个索引在该表中找到行。注意,该列完全独立于EXPLAIN输出所示的表的次序。这意味着在possible_keys中的某些键实际上不能按生成的表次序使用。

    (6)key:key列显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。

    (7)key_len:key_len列显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。注意通过key_len值我们可以确定MySQL将实际使用一个多部关键字的几个部分。

    (8)ref:ref列显示使用哪个列或常数与key一起从表中选择行。

    (9)rows:rows列显示MySQL认为它执行查询时必须检查的行数。

    (10)Extra:该列包含MySQL解决查询的详细信息。

    1. Distinct:MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。
    2. Not exists:MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。
    3. range checked for each record (index map: #):MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。对前面的表的每个行组合,MySQL检查是否可以使用range或index_merge访问方法来索取行。
    4. Using filesort:MySQL需要额外的一次传递,以找出如何按排序顺序检索行。通过根据联接类型浏览所有行并为所有匹配WHERE子句的行保存排序关键字和行的指针来完成排序。然后关键字被排序,并按排序顺序检索行。
    5. Using index:从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。当查询只使用作为单一索引一部分的列时,可以使用该策略。
    6. Using temporary:为了解决查询,MySQL需要创建一个临时表来容纳结果。典型情况如查询包含可以按不同情况列出列的GROUP BY和ORDER BY子句时。
    7. Using where:WHERE子句用于限制哪一个行匹配下一个表或发送到客户。除非你专门从表中索取或检查所有行,如果Extra值不为Using where并且表联接类型为ALL或index,查询可能会有一些错误。
    8. Using sort_union(...), Using union(...), Using intersect(...):这些函数说明如何为index_merge联接类型合并索引扫描。
    9. Using index for group-by:类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可以用来查询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。并且,按最有效的方式使用索引,以便对于每个组,只读取少量索引条目。

    通过相乘EXPLAIN输出的rows列的所有值,你能得到一个关于一个联接如何的提示。这应该粗略地告诉你MySQL必须检查多少行以执行查询。当你使用max_join_size变量限制查询时,也用这个乘积来确定执行哪个多表SELECT语句。

    🍅 Java学习路线:搬砖工逆袭Java架构师

    🍅 简介:Java领域优质创作者🏆、CSDN哪吒公众号作者✌ 、Java架构师奋斗者💪

    🍅 扫描主页左侧二维码,加入群聊,一起学习、一起进步 

    🍅 欢迎点赞 👍 收藏 ⭐留言 📝  

    展开全文
  • 索引

    万次阅读 2019-06-01 16:30:32
    什么是索引 索引的目的:帮助MySQL高效的获取数据的数据结构 常见的所以你查询算法:顺序查找、二分查找、二叉排序树查找、哈希散列法、分块查找、平衡多路搜索树B树(B-tree) 索引是在存储引擎层实现的,而...

    参考:https://www.cnblogs.com/barrywxx/p/4351901.html

    什么是索引

    • 数据库索引好比是一本书前面的目录,能加快数据库的查询速度。索引是对数据库表中一个或多个列的值进行排序的结构。如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息

    • 常见的查询算法:顺序查找、二分查找、二叉排序树查找、哈希散列法、分块查找、平衡多路搜索树B树(B-tree)

    • 索引是在存储引擎层实现的,而不是在服务器层实现的,所以不同存储引擎具有不同的索引类型和实现。

    建立索引的优缺点

    • 优点:

    1.大大加快数据的检索速度;
    2.创建唯一性索引,保证数据库表中每一行数据的唯一性;
    3.加速表和表之间的连接;
    4.在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间。

    • 缺点:

    1.索引需要占用数据表以外的物理存储空间
    2.创建索引和维护索引要花费一定的时间
    3.当对表进行更新操作时,索引需要被重建,这样降低了数据的维护速度。

    索引类型:

    根据数据库的功能,可以在数据库设计器中创建索引:唯一索引、主键索引和聚集索引。 尽管唯一索引有助于定位信息,但为获得最佳性能结果,建议改用主键或唯一约束。

    唯一索引: UNIQUE 例如:create unique index stusno on student(sno);
    表明此索引的每一个索引值只对应唯一的数据记录,对于单列唯一性索引,这保证单列不包含重复的值。对于多列唯一性索引,保证多个值的组合不重复。

    主键索引: primary key
    数据库表经常有一列或列组合,其值唯一标识表中的每一行。该列称为表的主键。 在数据库关系图中为表定义主键将自动创建主键索引,主键索引是唯一索引的特定类型。该索引要求主键中的每个值都唯一。当在查询中使用主键索引时,它还允许对数据的快速访问。

    https://blog.csdn.net/zhang150114/article/details/90573226
    主键和唯一索引都要求值唯一,但是它们还是有区别的:
    
    ①.主键是一种约束,唯一索引是一种索引;
    ②.一张表只能有一个主键,但可以创建多个唯一索引;
    ③.主键创建后一定包含一个唯一索引,唯一索引并一定是主键;
    ④.主键不能为null,唯一索引可以为null;
    ⑤.主键可以做为外键,唯一索引不行;
    

    聚集索引(也叫聚簇索引):cluster
    在聚集索引中,表中行的物理顺序与键值的逻辑(索引)顺序相同。一个表只能包含一个聚集索引。 如果某索引不是聚集索引,则表中行的物理顺序与键值的逻辑顺序不匹配。与非聚集索引相比,聚集索引通常提供更快的数据访问速度。

    索引的实现方式

    1.B+Tree 索引

    • MyISAM和InnoDB存储引擎的默认创建的是B+tree索引,Memory存储引擎也可以为B+tree索引(或者Hash索引)
    • InnoDB 的 B+Tree 索引分为主索引和辅助索引。

    主索引的叶子节点 data 域记录着完整的数据记录,这种索引方式被称为聚簇索引。因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引
    在这里插入图片描述

    辅助索引 的叶子节点的 data 域记录着主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到主索引中进行查找
    在这里插入图片描述
    在这里插入图片描述

    2. 哈希索引

    哈希索引能以 O(1) 时间进行查找,但是失去了有序性:

    无法用于排序与分组;

    只支持精确查找,无法用于部分查找和范围查找。

    InnoDB 存储引擎有一个特殊的功能叫“自适应哈希索引”,当某个索引值被使用的非常频繁时,会在 B+Tree 索引之上再创建一个哈希索引,这样就让 B+Tree 索引具有哈希索引的一些优点,比如快速的哈希查找

    3. 全文索引

    MyISAM 存储引擎支持全文索引,用于查找文本中的关键词,而不是直接比较是否相等。

    查找条件使用 MATCH AGAINST,而不是普通的 WHERE。

    全文索引使用倒排索引实现,它记录着关键词到其所在文档的映射。

    InnoDB 存储引擎在 MySQL 5.6.4 版本中也开始支持全文索引

    4. 空间数据索引

    MyISAM 存储引擎支持空间数据索引(R-Tree),可以用于地理数据存储。空间数据索引会从所有维度来索引数据,可以有效地使用任意维度来进行组合查询。

    必须使用 GIS 相关的函数来维护数据。

    展开全文
  • 通过对于城市拼音的首字母进行Index索引标识,通过右侧的字母索引列表,能够快速到定位到左侧的城市列表信息,找到指定的字母Index下的所有城市列表信息数据,并且进行显示,实现了VantUI中IndexBar索引导航栏功能。...
    一、思路说明:

    这里是以城市列表数据作为索引,通过对于城市拼音的首字母进行Index索引标识,通过右侧的字母索引列表,能够快速到定位到左侧的城市列表信息,找到指定的字母Index下的所有城市列表信息数据,并且进行显示,实现了VantUI中IndexBar索引导航栏功能。

    二、代码实现:
    <template>
        <div class="city_body">
            <div class="city_list">
                <div class="city_hot">
                    <h2>热门城市</h2>
                    <ul class="clearfix">
                        <li v-for="item in hotList" :key="item.id">{{ item.nm }}</li>
                    </ul>
                </div>
                <div class="city_sort" ref="city_sort">
                    <div v-for="item in cityList" :key="item.index">
                        <h2>{{ item.index }}</h2>
                        <ul>
                            <li v-for="itemList in item.list" :key="itemList.id">{{ itemList.nm }}</li>
                        </ul>
                    </div>
                </div>
            </div>
            <div class="city_index">
                <ul>
                    <li v-for="(item, index) in cityList" :key="item.index"  @touchstart="handleToIndex(index)">{{ item.index }}</li>
                </ul>
            </div>
        </div>
    </template>
        
    <script>
    
    export default {
        name: 'City',
        data() {
            return {
                cityList: [],
                hotList: []
            }
        },
        mounted() {
            this.axios.get('/api/cityList').then((res) => {
                // console.log(res);
                // 数据格式: [ { index: 'A', list: [{ nm: '北京', id: 1}]}]
                var msg = res.data.msg;
                if( msg === 'ok') {
                    var cities = res.data.data.cities;
                    var {cityList, hotList} =  this.formatCityList(cities);
                    this.cityList = cityList;
                    this.hotList = hotList;
                }
            });
        },
        methods: {
            formatCityList(cities) {
                var cityList = [];
                var hotList = [];
    				
    			// 热门城市列表信息		
                for(var i=0;i<cities.length; i++) {
                    if(cities[i].isHot === 1){
                        hotList.push( cities[i]);
                    }
                }
                
                // 城市列表信息
                for(var i=0; i<cities.length; i++) {
                    var firstLetter = cities[i].py.substring(0,1).toUpperCase();
                    if(toCom(firstLetter)) {  // 新添加到索引中
                        cityList.push({index: firstLetter, list: [{ nm: cities[i].nm, id: cities[i].id}]});
                    }else { // 累计到已有的索引
                        for(var j=0; j<cityList.length; j++){
                            if(cityList[j].index === firstLetter) {
                                cityList[j].list.push(  { nm: cities[i].nm, id: cities[i].id} );
                            }
                        }
                    }
                }
    
                // 城市数据索引index的排序
                cityList.sort((n1,n2) => {
                    if(n1.index > n2.index) {
                        return 1;
                    }
                    else if (n1.index < n2.index) {
                        return -1;
                    } else {
                        return 0;
                    }
                })
    
                // 判断index是否存在于cityList中
                function toCom(firstLetter) {
                    for(var i=0;i<cityList.length;i++){
                        if(cityList[i].index === firstLetter) {
                            return false;
                        }
                    }
                    return true;
                }
    
                // console.log(cityList);
                // console.log(hotList);
                return {
                    cityList,
                    hotList
                }
            },
            // 点击右侧索引,左侧城市列表也滚动到指定的位置
            handleToIndex(index) {
                var h2 = this.$refs.city_sort.getElementsByTagName('h2');
                this.$refs.city_sort.parentNode.scrollTop = h2[index].offsetTop;
            }
        }
    }
    </script>
    
    //  style样式代码
    <style scoped>
    #content .city_body{ margin-top: 45px; display: flex; width:100%; position: absolute; top: 0; bottom: 0;}
    .city_body .city_list{ flex:1; overflow: auto; background: #FFF5F0;}
    .city_body .city_list::-webkit-scrollbar{
        background-color:transparent;
        width:0;
    }
    .city_body .city_hot{ margin-top: 20px;}
    .city_body .city_hot h2{ padding-left: 15px; line-height: 30px; font-size: 14px; background:#F0F0F0; font-weight: normal;}
    .city_body .city_hot ul li{ float: left; background: #fff; width: 29%; height: 33px; margin-top: 15px; margin-left: 3%; padding: 0 4px; border: 1px solid #e6e6e6; border-radius: 3px; line-height: 33px; text-align: center; box-sizing: border-box;}
    .city_body .city_sort div{ margin-top: 20px;}
    .city_body .city_sort h2{ padding-left: 15px; line-height: 30px; font-size: 14px; background:#F0F0F0; font-weight: normal;}
    .city_body .city_sort ul{ padding-left: 10px; margin-top: 10px;}
    .city_body .city_sort ul li{ line-height: 30px; line-height: 30px;}
    .city_body .city_index{ width:20px; display: flex; flex-direction:column; justify-content:center; text-align: center; border-left:1px #e6e6e6 solid;}
    </style>
    
    展开全文
  • Android数据库高手秘籍(十二),LitePal的索引功能

    万次阅读 多人点赞 2020-08-11 08:13:46
    我发现今年我的技术产出真的是很不错,自从《第一行代码 第3版》出版之后,我空余出来了大量的时间,不仅频繁地更新和...回到今天的主题,LitePal自上次3.1版本支持了事务之后,基本数据库该有的功能差不多都具备了,

    本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭霖 即可关注,每个工作日都有文章更新。

    我发现今年我的技术产出真的是很不错,自从《第一行代码 第3版》出版之后,我空余出来了大量的时间,不仅频繁地更新和维护自己编写的开源库,还参加了多场GDG活动与大家分享技术。

    目前我手上正在维护的开源库主要是LitePalPermissionX这两个,属于交叉维护的状态,升级完了这个就抓紧去写另外一个。其实今年我本来还准备再写一个新的开源项目,但是现在不知是否还能够抽出足够的时间,思路已完备,就是迟迟没动手。

    回到今天的主题,LitePal自上次3.1版本支持了事务之后,基本数据库该有的功能差不多都具备了,但是长久以来,始终还有一个呼声,就是有些朋友希望LitePal可以支持索引。

    关于索引这个功能,我在做LitePal 1.x版本的时候就考虑过加入,当时代码写了有一半左右,但是由于测量下来结果不理想,最后又移除了这部分功能。为什么不理想呢?因为在移动设备的数据库上,索引其实并不能起到什么太大的作用,只有在数据量非常大的时候,索引才能体现出查询效率的优势,而移动设备通常都不会有非常大的数据量。

    但是不支持索引,最后可能会成为我的一块心病,因为时不时就会有朋友要求LitePal支持这个功能。所以我决定,在LitePal 3.2版本中加入对索引的支持,补齐这块功能缺失。同时这也是3.x系列的最后一个版本,下个版本将会有较大的架构变动,LitePal会逐渐向Room的设计与用法靠齐。

    另外,我要提醒大家的是,虽然LitePal 3.2版本支持了索引,但是我认为绝大部分的朋友还是不应该使用它。因为第一,你真的用不到它(后面会解释为什么);第二,怕你用不好它(错误地使用索引反而会降低效率)。所以,当你真的清楚自己在做什么的时候,请再使用索引。

    读到这里,是不是有小伙伴觉得我一直在劝退?没错,但是并不影响你阅读本篇文章,因为了解一下什么是索引也是挺好的,即使你用不到它。


    什么是索引?

    简而言之,索引是一种用于加快数据库查询的工具。

    在我们传统的印象中,数据库的查询速度都是非常快的,通过一条SQL语句在数据库中查找满足指定条件的数据几乎是瞬间就可以完成的。

    那么你有没有想过,数据库是如何从海量数据当中找出那些满足指定条件的数据呢?

    其实并没有什么特别的技术,就是将数据库表中所有的数据全部都查询一遍即可,也就是所谓的全表搜索。

    听上去有些让人不敢相信,但事实确实是如此,只不过得益于数据库本身高效的执行效率,所以查询速度通常都非常快。

    在SQLite中,想要知道你的查询语句是否是全表搜索,只需要在你的查询语句之前加入explain query plan关键字即可,如下图所示。

    可以看到,detail这一栏当中的信息是SCAN TABLE Song,这就意味着SQLite将Song这张表全表都搜索了一遍。

    这种全表搜索的方式只要是正常人的思维都知道是有问题的,因为随着表中的数据越来越多,全表搜索的时间也注定会越来越长。比如说像淘宝这种拥有几亿用户的数据库表,如果我每次登录都需要将这几亿条用户数据全部搜索一遍,从中找出我登录的那个账号,这显然是不切实际的。

    那么如何解决这个问题呢?为了能够从海量数据当中快速找到指定的数据,所有的主流数据库都会提供索引这个功能。

    索引的工作原理说简单也简单,说复杂也复杂,那么我尽量往简单的说。简单来讲,索引的工作原理本质上就是二分查找。

    二分查找是一种很神奇的算法,它可以将查找的时间复杂度降低一个量级,从而显著地提升查询效率,但前提是要求数据必须有序。

    举一个形象的例子,假设一个数组当中有20亿条数据,我想要在这个数组中找到其中某一条数据,如果使用遍历查询的方式,那么最坏情况下需要查询20亿次才行。

    而如果使用二分查找呢?我们可以每次取中间值,然后舍弃不满足条件的那一半数据,重复进行以上操作,这样最多只需要查询31次就可以找到结果。

    (图片来源于网络)

    有没有被这两个不同的量级吓到?

    不过数据库中存储的是非常复杂的关系型数据,是不能用简单的数组来表示的,并且维护一个有序的数组本身就是一件成本很高的事情。

    这个时候就需要引入另外一种高级数据结构了:二叉搜索树。二叉搜索树是一种树状的数据结构,它由根结点、左子树、右子树三部分组成,并且左子树的值总是小于根结点,右子树的值总是大于根结点。

    (图片来源于网络)

    有没有发现?二叉搜索树也是可以运用二分查找特性的,因为它每次也可以舍弃一半不满足条件的数据。另外,维护一个二叉搜索树并不像维护一个有序数组那样成本很高,因为已经有很多现成的解决方案了,比如我们所熟知的红黑树。

    然而二叉搜索树的方案仍然不适用于数据库索引,主要是因为索引并不只是存储于内存当中,还要存储在硬盘当中。而硬盘的存储是分数据块的,不同数据块之间的磁盘读取也是比较耗时的。假设我们使用二叉搜索树来作为索引的存储结构,那么树的高度就会很高,从而使用索引查询时为了读取数据可能要跨很多个磁盘的数据块,导致查询效率降低。

    因此,为了降低树的高度,几乎所有主流数据库都是使用N叉树这种数据结构来建立索引的。N叉树和二叉树类似,只是它的每个根节点可以有多个子树,而不像二叉树那样限定只能有两个。

    根据我查询到的资料,MySQL使用的N叉树(准确讲是B+树),N大概是1200左右。我们可以试算一下,1200的三次方大概是17亿,也就是说N叉树的高度只需要3层,就可以存储二叉树将近31层的数据。这样就在内存查询效率和磁盘查询效率之间找到了一个比较合适的平衡点。

    虽然不同数据库在具体的实现方面还会有些不同,但大体的思路都是差不多的。


    索引的用法

    了解了什么是索引之后,接下来我们看一下索引的具体用法。

    索引的用法是非常简单的,至少在LitePal当中索引的用法非常简单,毕竟LitePal当中一切都非常简单。

    如果你想要给一个字段添加索引,只需要在该字段的上方加上一个@Column注解,并指定index = true即可,如下所示:

    public class Song extends LitePalSupport {
    	
    	@Column(index = true)
    	String name;
    	
    	String lyric;
    	...
    }
    

    然后升级一下litepal.xml当中的版本号,这样LitePal就会自动给Song表的name字段加上索引。

    没错,这样就OK了。虽然为了支持索引这个功能我着实编写了不少代码,但是对于使用者而言,你所需要做的就只有这么多。

    现在我们可以再使用刚才的explain query plan关键字,来检查一下同样的查询语句:

    可以看到,detail这一栏中的信息和之前不一样了,说明现在我们的查询语句已经不是全表搜索了,而是会使用索引来加速查询。


    索引的效果

    那么使用了索引之后,效果到底如何呢?说实话,想要验证索引的效果确实是不容易的,因为在移动端我们通常根本就没有海量的数据进行验证。

    但是没有经过验证的索引功能是没有说服力的,所以我还是尽可能想办法把验证的结果展示给大家。

    既然没有海量数据,那么就自己造呗。

    LitePal的存储效率其实还是比较不错的,借助LitePal.saveAll()方法,存储10000条数据耗时大概在700毫秒左右,只需7秒时间我就可以模拟出10万条数据。代码如下:

    int loopCount = 10;
    for (int i = 0; i < loopCount; i++) {
    	List<Song> songList = new ArrayList<>();
    	for (int j = 0; j < 10000; j++) {
    		Song song = new Song();
    		song.setName("name" + i * loopCount + j);
    		song.setLyric("lyric" + i * loopCount + j);
    		songList.add(song);
    	}
    	LitePal.saveAll(songList);
    }
    

    那么就先用10万条数据来进行测试吧,首先检查一下Song表中的总数据量:

    是10万条,准确无误。

    然后使用如下查询代码从这10万条数据当中查找指定的数据:

    long start = System.currentTimeMillis();
    LitePal.where("name = ?", "name10086").find(Song.class);
    long end = System.currentTimeMillis();
    Log.d("TAG", "find with index cost " + (end - start) + "ms");
    

    结果如下图所示。

    可以看到,借助索引,我们在10万条数据当中查询指定数据只需要6毫秒,这个效率可以算是相当不错了吧?

    那么如果不使用索引,全表搜索的情况下查询需要多久呢?我们同样来试一试。

    lyric这一列是没有添加索引的,现在我们根据这一列作为条件进行查询,那么就会进行全表搜索,代码如下所示:

    long start = System.currentTimeMillis();
    LitePal.where("lyric = ?", "lyric10086").find(Song.class);
    long end = System.currentTimeMillis();
    Log.d("TAG", "find without index cost " + (end - start) + "ms");
    

    结果如下图所示。

    可以看到,总耗时是23毫秒。

    虽然23毫秒是6毫秒的4倍左右,但是对于移动设备而言,23毫秒并不是很长的耗时,基本上在你完全感知不到的情况下查询就结束了。

    并且这是10万条数据,通常我们在数据库表当中存储的数据还远远到不了10万条,这样索引能带来的性能优势会进一步减少。

    当然我们都知道,随着数据量越来越多,索引的性能优势也会越来越大,但是即使我将数据量放大到了100万条,全表搜索的速度仍然还是很快,基本都可以在150ms左右的时间完成。

    这也是为什么LitePal长期以来不支持索引的原因,因为移动端真的存储不了那么多的数据,即使加入了索引,所能带来的性能提升也非常有限。

    但是如果表中存储的数据量真的极大,那么是一定要用索引的,所以这项技术在服务器端的数据库当中使用得相当普遍。

    秉着严谨的态度,我又将表中的数据扩大到了1000万条。这个量级的数据已经不是很好模拟了,我存储这些数据就花了十几分钟的时间,而且还要保证手机存储空间充足,1000万条数据可能会占用1G左右的空间(不同手机会有差异,我在另外一台手机上测试是700M的空间)。


    这种数据量级下,我们先来试一试借助索引的查询速度:

    仍然很快,10毫秒的时间就可以将数据查询出来。

    那么不使用索引呢?我们也来试一下:

    这个对比差距就比较大了,不使用索引的情况下,1000万条数据全表搜索会耗费2.5秒的时间,这是一个足够长到让用户能够明显感受到卡顿的时间了。

    所以,像服务器的数据库当中动辄可能会有几亿几十亿的数据,这个时候是必须要使用索引的,而移动端可能很难想象会有这种数据量级的场景。


    到底应不应该使用索引呢?

    写到这里,我们已经把什么是索引,LitePal中索引的用法,以及索引实际的效果全部都分析完了。

    那么最后还剩一个问题,就是我们到底应不应该使用索引?

    其实应不应该使用要看你到底用不用得着,我的个人看法是绝大部分人应该是用不着的,因为移动端的数据库几乎不太可能会存储这么多的数据。而在用不着的情况下强行使用索引,反而可能会降低你的其他数据库操作的效率(比如增删改),因为维护索引的B+树也是需要耗时的。

    另外,添加索引的列尽量要保证数据重复率非常低才行,不然索引将会失去效果。这个也很好理解,比如我给性别这一列加上索引,由于性别就只有男女两种,1000万条数据我可能要查询500万条才能把指定性别的所有数据查询出来,这种索引基本是没有作用的。

    而如果你对索引本身就已经非常熟悉了,并且完全清楚自己在做什么的时候,请使用索引,LitePal已经完全为你准备好了。


    如何升级

    升级的方式很简单,只需要在build.gradle中修改一下配置即可:

    dependencies {
        implementation 'org.litepal.guolindev:core:3.2.0'
    }
    

    3.2.0版本中的所有的功能都是向下兼容的,因此你的升级不用付出任何成本。

    LitePal的项目主页地址是:

    https://github.com/guolindev/LitePal

    另外,本篇文章是写给已经有LitePal基础的人看的,帮助他们快速了解3.2.0版本的新特性。如果你之前并没有接触过LitePal,那么可以阅读我写的技术专栏《Android数据库高手秘籍》,里面有非常详尽的LitePal使用讲解。

    如果想要学习Kotlin和最新的Android知识,可以参考我的新书 《第一行代码 第3版》点击此处查看详情


    关注我的技术公众号,每天都有优质技术文章推送。

    微信扫一扫下方二维码即可关注:

    展开全文
  • 索引的十一种功能

    千次阅读 2009-05-10 01:15:00
    索引是个既稳定又开放的信息结构,它有十一种功能。1 分解功能把文献中的资料单元(如篇名、机构、短语、概念、物名、地名、书名、人名、字词、符号等)一一分解,这就是索引的分解功能。它是索引工作的起跑线和索引...
  • 收集统计信息导致索引被监控

    千次阅读 2013-03-26 17:33:34
    对于索引的调整,我们可以通过Oracle提供的索引监控特性来跟踪索引是否被使用。尽管该特性并未提供索引使用的频度,但仍不失为我们参考的... 1、基于Oracle 10g 收集统计信息索引被监控情形scott@CNMMBO> select * fro
  • mysql索引

    千次阅读 2019-08-18 10:33:10
    一句话简单来说,索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。一本 500 页的书,如果想快速找到其中的某一个知识点,在不借助目录的情况下,那估计得找一会儿。同样,对于数据库的表而言,索引...
  • Exadata中最有用的功能-存储索引

    千次阅读 2012-08-14 16:28:50
    Exadata中最有用的功能-存储索引 前所未闻的存储索引是Exadata中最有用的功能,它不是像Oracle的B树索引或者位图索引那样传统的存储在数据库中的索引,事实上,它在传统意义上甚至根本不能算是索引。我们无法通过...
  • 数据库索引

    千次阅读 多人点赞 2019-08-20 22:49:54
    索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。数据库索引好比是一本书前面的目录,能加快数据库的查询速度。索引分为聚簇索引和非聚簇索引两种,聚簇索引是按照...
  • Mysql索引

    千次阅读 2019-12-02 13:21:26
    好记忆不如烂笔头, 能记下点什么, 就记下点什么, 方便后期的巩固. 一.介绍 1.什么是索引? 2.... 1.MySQL的索引分类 2.各索引应用场景 3.索引类型 4.操作索引 5.唯一索引 四.测试...
  • lucene索引结构(二)--域(Field)信息索引

    千次阅读 2012-07-22 19:46:56
    1. 域(Field)的元数据信息(.fnm)文件分析 1.1 作用  我们在为文档建立索引的时候,会为文档添加不同的域(字段)来进行索引,使得索引结构能满足更多的查询语法。例如一个文档集被索引了author,modifydate字段,...
  • Lucene倒排索引简述 之索引

    千次阅读 2018-09-27 09:57:42
    Lucene倒排索引的核心内容,索引表,你对这部分真的熟悉了吗?那你知道FST用什么地方吗?FST又存储了什么内容呢?有什么功能呢?关于Burst-Trie,你知道Lucene是如何采用它的思想来加速Lucene搜索性能的吗?
  • MongoDB 提供了多样性的索引支持,索引信息被保存在system.indexes 中,且默认总是为_id创建索引,它的索引使用基本和MySQL 等关系型数据库一样。其实可以这样说说,索引是凌驾于数据存储系统之上的另一层系统,所以...
  • 索引的作用:可以快速的查询数据库中的特定信息(加速检索数据库中表的数据)。 https://www.cnblogs.com/little-orangeaaa/p/9707850.html 先提出几个问题? 为什么要给表加主键? 为什么加索引后会是检索变快...
  • 索引概念

    千次阅读 2016-07-16 12:02:30
    索引,使用索引可快速访问数据库表中的特定信息索引是对数据库表中一列或多列的值进行排序的一种结构。 在关系数据库中,索引是一种与表有关的数据库结构,它可以使对应于表的SQL语句执行得更快。索引的作用...
  • SQL索引

    千次阅读 2016-04-06 11:47:53
    SQL索引在数据库优化中占有一个非常大的比例, 一个好的索引的设计,可以让你的效率提高几十甚至几百倍,在这里将带你一步步揭开他的神秘面纱。  1.1 什么是索引?  SQL索引有两种,聚集索引和非聚集索引索引...
  • Oracle 索引监控与外键索引

    千次阅读 2013-03-29 10:49:56
    之所以这么说,是因为在Oracle 10g 中收集统计信息时会导致索引被监控,此并非sql语句而产生。而在11g则不会出现类型的情形。其次对于存在子表存在外键的情形,对于主表进行操作时是否会导致索引被监控呢?下面描述...
  • 非聚簇索引:数据存储和索引分开放,索引结构的叶子节点指向了数据的对应行,myisam通过 key_buffer 把索引先缓存到内存中,当需要访问数据时(通过索引访问数据),在内存中直接搜索索引,然后通过索引找到磁盘...
  • 5.2 Lucene索引器: 5.2.1 Lucene索引介绍 ...文档索引 是 Lucene系统的核心功能。 有专门的API用来实现索引的建立和管理功能。可处理多种格式的文档,如磁盘文件、电子邮件地址、网页及数据库记录等。 Lucene
  • 于是会产生索引索引索引索引索引索引... OLAP:对历史数据的分析,比如Hive OLTP:关系型数据库都是OLTP,要求在最短时间内返回最终结果 为什么选择B+树? MySQL B+ 树的根节点、叶子结点都存储与磁盘中。...
  • inoodb 是使用b+树来实现索引功能的。 一、 B+树和B树的区别 B树种的同一键不会出现多次,可能在叶子节点上也可能在非叶子节点上; b+树的键一定会出现在叶子节点上,同时也可能在非叶子节点上重复出现。 ...
  • 前言: 从2008开始,引入了一个增强非聚集索引的新功能——过滤索引(filter index),可以使用带有where条件的语句来创建非聚集索引,过滤掉不需要的数据,降低索引的维护开销和存储空间,提高查询性能。...
  • Mysql索引详解

    千次阅读 多人点赞 2019-06-29 21:58:33
    索引的优缺点)1、索引产生的意义2、索引的优缺点二、索引的分类三、B树-数据库索引原理1、B树(平衡多路查找树)2、B+树3、B+树的优势四、聚合索引(InNoDB存储引擎)与非聚合索引(MyISAM存储引擎)1、聚合索引2...
  • MySQL索引详解之索引的数据结构

    千次阅读 2020-04-21 18:53:22
    很多人对数据库索引可能都是知其然却不知其所以然,对索引没有很深入的理解,在使用过程中也一知半解,导致没有办法准确高效地使用索引,甚至存在不少误用的情况,导致使用索引反而降低了系统的性能。下面就以MySQL...
  • SQL Server 索引管理——禁用无用索引

    千次阅读 2019-05-28 13:38:34
    为了保险起见,如果我们使用的是SQLServer 2005及以后版本,我们可以使用其新增加的功能索引禁用。这样如果后期发现禁用掉的索引是需要的,我们就可以及时重建索引,保证数据库的性能,如果通过足够时长的观察,...
  • MySQL基本概念--索引&索引类型

    千次阅读 2014-03-06 23:38:10
    索引是快速搜索的关键。MySQL索引的建立对于MySQL的高效运行是很重要的。下面介绍几种常见的MySQL索引类型。 在数据库表中,对字段建立索引可以大大提高查询速度。假如我们创建了一个 mytable表: CREATE TABLE ...
  • MySQL数据库索引

    万次阅读 多人点赞 2018-09-23 09:31:41
    索引是什么 索引有哪些结构 数据库有哪些索引 唯一索引 聚簇索引与非聚簇索引 全文索引 使用索引一定能提高查询性能吗? 哪些情况下设置了索引但是无法使用 哪些情况下需要设置索引、哪些情况下不需要 什么...
  • 文章目录情景解决方案 情景 在使用 Elasticsearch 的时候,...其中,第一种方式是功能最全的,Elasticsearch 的所有操作情形,都可以通过命令来实现; 但与之相对的,第二种方式就显得相形见绌了,因为 Elasticsea...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 498,929
精华内容 199,571
关键字:

信息索引的功能