.MYI
和innodb中的.idb
都是存放索引的文件。索引结构 | 说明 |
---|---|
B+TREE索引 | 常见索引,大部分引擎都支持 |
Hash索引 | 底层使用hash表实现,只有精确匹配索引列的查询才有效,不支持范围查询 |
R-tree/空间索引 | MyISAM引擎的一个特殊索引类型,用于存储地理空间类型,使用较少 |
Full-text/全文索引 | 倒排索引,类似Lucene、Es |
Hash索引的形成原理,以人员表中的name列索引为例:
为键值对,存放至HashMap结构中,其中hash(name)
表示name列的hash值,hash(row)
表示步骤一中计算的对应行数据的hash值。Hash索引特点:
存储引擎的应用
双向链表
(注意下图展示的是经典B+树是单向链表,不是MYsql中的B+索引结构)
为什么innodb使用B+树索引,B+树索引的优点:
聚集索引在表中必须有,而且只有一个
,否则表数据没办法存放。假如innodb设置的页大小是16k,一行数据平均有1k,一个指针占用6个字节,主键key使用bigInt占用8个字节,请问:高度为2和3时分别大约可以存储多少条数据?
n*8+(n+1)*6 = 16*1024
show [session | global] status
查看服务器状态信息,可以查看当前数据的增删改查次数:show global status like 'Com_______'
。根据这个命令,可以查到Com_insert/Com_select/Com_update等执行的次数,session代表当前会话,global代表所有会话。/etc/my.cnf
中配置,配置后慢sql日志会被默认记录在/var/lib/mysql/localhost-slow.log
文件中) show variables like 'slow_query_log'
/etc/my.cnf
文件,打开慢sql记录,重启
mysql后生效:# 开启慢sql日志记录
slow_query_log=1
# 设置慢日志的时间为2s
long_query_time=2
select @@have_profiling
,再查看profiling是否开启:select @@profiling
set profiling = 1
进行开启,,无需重启数据库。# 查看每一条SQL耗时
show profiles;
# 根据query_id查看sql各阶段耗时
show profile for query query_id;
# 查看指定query_id的sql语句CPU使用情况
show profile cpu for query query_id;
type possible_keys key key_len rows Extra
): using index condition
:查询使用到了索引,但是需要回表进行查询数据,如果查询结果列中存在没有索引的列,会出现这类提示,例如select *
using where using index
:查找使用了索引,但是结果列在索引列中都可以找到,不用回表查询操作。这种效率肯定比上面的高,推荐尽量使用这种。null
,也表示要进行回表查询。select *
,这样会大大减少回表操作。where id = 1
肯定会比where A = 'a'
效率更高,即使A也是索引列,因为id作为聚集索引列,行数据挂在B+树叶子节点下,检索到1之后直接可以取出。而根据二级索引列A查询到后,还需要回表操作。create index idx_name_6 on tb_name(A(6))
,这种索引名称一般加个_n
,用来直观区分前缀索引及截取长度。select count(distinct substring(column_name, 1, n)) / count(*) from tb_name
,在公式计算结果接近于1的前提下,可以从大到小逐渐调整n的值,并得到最后合适的结果。公式的意思就是截取最少的前缀,以保证可以最大程度地覆盖所有的行数据。select * from user where address = '山东省济南市历城区科创路1000号'
为例(已经建立了address长度为6的前缀索引): 山东省济南市历城区科创路1000号
进行全长匹配,如果全长匹配上了,就认为这一条是想要的数据;如果没匹配上,回到步骤2中根据B+树的双向链表结构,对叶子节点进行下一条的检索,直到本步骤匹配上为止。where A='a' and B > 0 and C='c'
中,C='c'
就会失效,因为在B列范围查询的右侧。B>=0
,右侧的就不会失效,所以在真实只用中,尽量用>=
而不是>
A= 0 or B = 1
,如果A有索引而B没有,则这个语句不会走索引。用来在sql语句中提示mysql用哪个索引
use index()
,select * from tb_name use index(index_name) where A =''
。ignore index()
force index()