MySQLのインデックス関連の知識と、多くの場合、インタビューの質問

共通のインタビューの質問

  まず、インデックスに関連する一般的な面接の質問の導入は、私たちはより客観的な指標に関連するコンテンツを学びましょう

    • Q:最も一般的なデータベースのクエリ最適化アプローチが遅い何ですか?
      • クラスメイトのA:インデックス化。
    • Q:なぜ遅いクエリを最適化するためにインデックス化されていますか?
      • 同級生A:...私は知りません
      • 学生B:インデックスはMySQLのような、実際のクエリの最適化されたデータ構造であるので、インデックスはB +ツリーは、クエリの速度を最適化することが可能なデータ構造である一方で、すばやくデータを検索するためにインデックスを使用することができ、B +ツリーの実装である、私たちはすることができますクエリの最適化。
    • Q:あなたは、検索をスピードアップすることができますどのようなデータ構造を知っていますか?(...ピットを感じるここにこの質問を聞きます)
      • 学生B:ようにハッシュテーブル、完璧にバランスの取れたバイナリツリー、Bツリー、B +木と。
    • Q:これらのデータ構造は、クエリの速度を最適化することができるので、なぜそのようなMySQLのB +ツリーを使用することを選ぶのか?
      • 学生B:...私は知りません
    • Q:titlesテーブル、主キーEMPNO、タイトル、FROMDATE三つのフィールド。そして、次の文は、インデックス、それを使うのだろうか?
      *選択から EMP_NO = 1がemployees.titles 
      選択 * からタイトル= employees.titles ' 1 ' 
      を選択 * から EMP_NO = employees.titles ' 1 ' andtitle = 1 
      を選択 * からタイトル= employees.titles ' 1 ' andemp_no = 1
    • Q:なぜ、ハッシュテーブル、完璧にバランスの取れたバイナリツリー、Bツリー、B +ツリーは、クエリを最適化することができ、その理由のような唯一のMySQLのB +ツリーの?ハッシュテーブルの特徴は何ですか?
    • :そのようなテーブルがある場合は(テーブル名:三国):                                                                                                                                                                        

    さて、名前フィールドのハッシュインデックスを作成し、ランダムなハッシュアルゴリズムを計算された配列のインデックスに対応するフィールドの値を書き留め、そのハッシュ衝突が発生することがあります。このようなインデックス構造のためだから、今、次のSQL文を実行します:
選択* から名=三国周瑜

「周瑜」は、直接配列インデックスのうち、ハッシュアルゴリズムによって計算することができ、その後、データラッチラインに対応するアドレス、およびその行のデータのクエリを取得するために、データとデータから直接削除されます。だから我々は、次のSQL文を実行した場合:

選択* から名>三国周瑜

これは、ハッシュテーブルの特性を素早く正確に照会する能力であるため、非力ですが、範囲クエリをサポートしていません。

それは完全にバランスの取れたバイナリツリーがある場合は?

上記または完全な平衡二分木を示すテーブルデータを以下の(簡単にするために、アドレスデータに対応する図に描かれていません。)。

図は、各ノードは、実際には4つの部分で構成されていなければなりません。

  • 左ポインタ、左の部分木を指し
  • キー
  • キーに対応するアドレスデータを格納します
  • 右部分木を指す右のポインタ、

また、バイナリの列があることを思い出したする必要があり、単に私たちが見ているのだ「周瑜」は、二回(初回曹操、二度目周瑜)ビハール州を見つける必要がある場合は「左が右よりも小さい」という意味もう一度ギリシャのテーブルへ。完璧にバランスの取れたバイナリツリーを命じているのでそして、それはまた、検索の範囲によってサポートされています。

 

Bツリーの場合?

上記またはBツリーによって表されるテーブルデータ以下(簡単にするために、アドレスデータに対応する図に描かれていません。)。

 

同一の要素には、Bツリーのノードが複数の要素を格納することができるので、Bツリーは、「短い」は、完全な平衡二分木よりも表すように求めることができます。

 

B +木の場合は?

B +ツリーを表すテーブルデータ上または下(簡単にするために、アドレスデータに対応するが、図には描かれていません。)

 我々は、理由はリーフノードでB +ツリーの冗長非リーフノードの「脂肪」を表現するために、Bツリーと同じ元素、B +ツリーを検索し、リーフノードとの間のポインタとリンクすることができます。

 

そして、どのような利点最終的にはB +ツリー?

  这里我们用“反证法”,假如我们现在就用完全平衡二叉树作为索引的数据结构,我们来看一下有什么不妥的地方。实际上,索引也是很“大”的,因为索引也是存储元素的,我们的一个表的数据行数越多,那么对应的索引文件其实也是会很大的,实际上也是需要存储在磁盘中的,而不能全部都放在内存中,所以我们在考虑选用哪种数据结构时,我们可以换一个角度思考,哪个数据结构更适合从磁盘中读取数据,或者哪个数据结构能够提高磁盘的IO效率。回头看一下完全平衡二叉树,当我们需要查询“张飞”时,需要以下步骤:

  1. 从磁盘中取出“曹操”到内存,CPU从内存取出数据进行笔记,“张飞”<“曹操”,取左子树(产生了一次磁盘IO)
  2. 从磁盘中取出“周瑜”到内存,CPU从内存取出数据进行笔记,“张飞”>“周瑜”,取右子树(产生了一次磁盘IO)
  3. 从磁盘中取出“孙权”到内存,CPU从内存取出数据进行笔记,“张飞”>“孙权”,取右子树(产生了一次磁盘IO)
  4. 从磁盘中取出“黄忠”到内存,CPU从内存取出数据进行笔记,“张飞”=“张飞”,找到结果(产生了一次磁盘IO)

  同理,回头看一下B树,我们发现只发送三次磁盘IO就可以找到“张飞”了,这就是B树的优点:一个节点可以存储多个元素,相对于完全平衡二叉树所以整棵树的高度就降低了,磁盘IO效率提高了。

  而B+树是B树的升级版,只是把非叶子节点冗余一下,这么做的好处是为了提高范围查找的效率。

  到这里可以总结出来,Mysql选用B+树这种数据结构作为索引,可以提高查询索引时的磁盘IO效率,并且可以提高范围查询的效率,并且B+树里的元素也是有序的。

那么,一个B+树的节点中到底存多少个元素合适呢?

  其实也可以换个角度来思考B+树中一个节点到底多大合适?

  答案是:B+树中一个节点为一页或页的倍数最为合适。因为如果一个节点的大小小于1页,那么读取这个节点的时候其实也会读出1页,造成资源的浪费;如果一个节点的大小大于1页,比如1.2页,那么读取这个节点的时候会读出2页,也会造成资源的浪费;所以为了不造成浪费,所以最后把一个节点的大小控制在1页、2页、3页、4页等倍数页大小最为合适。

那么,Mysql中B+树的一个节点大小为多大呢?

  这个问题的答案是“1页”,这里说的“页”是Mysql自定义的单位(其实和操作系统类似),Mysql的Innodb引擎中一页的默认大小是16k(如果操作系统中一页大小是4k,那么Mysql中1页=操作系统中4页),可以使用命令SHOW GLOBALSTATUS like 'Innodbpagesize'; 查看。并且还可以告诉你的是,一个节点为1页就够了。

为什么一个节点为1页(16k)就够了?

  解决这个问题,我们先来看一下Mysql中利用B+树的具体实现。

  Mysql中MyISAM和innodb使用B+树

  通常我们认为B+树的非叶子节点不存储数据,只有叶子节点才存储数据;而B树的非叶子和叶子节点都会存储数据,会导致非叶子节点存储的索引值会更少,树的高度相对会比B+树高,平均的I/O效率会比较低,所以使用B+树作为索引的数据结构,再加上B+树的叶子节点之间会有指针相连,也方便进行范围查找。上图的data区域两个存储引擎会有不同。

 

 MyISAM中的B+树

  MYISAM中叶子节点的数据区域存储的是数据记录的地址,MyISAM存储引擎在使用索引查询数据时,会先根据索引查找到数据地址,再根据地址查询到具体的数据。并且主键索引和辅助索引没有太多区别。

 主键索引

 

 

辅助索引

  

 

 InnoDB中的B+树

   InnoDB中主键索引的叶子节点的数据区域存储的是数据记录,辅助索引存储的是主键值

主键索引

辅助索引

 

 Innodb中的主键索引和实际数据时绑定在一起的,也就是说Innodb的一个表一定要有主键索引,如果一个表没有手动建立主键索引,Innodb会查看有没有唯一索引,如果有则选用唯一索引作为主键索引,如果连唯一索引也没有,则会默认建立一个隐藏的主键索引(用户不可见)。另外,Innodb的主键索引要比MyISAM的主键索引查询效率要高(少一次磁盘IO),并且比辅助索引也要高很多。所以,我们在使用Innodb作为存储引擎时,我们最好:

  1. 手动建立主键索引
  2. 尽量利用主键索引查询

 

回到我们的问题:为什么一个节点为1页(16k)就够了?

  对着上面Mysql中Innodb中对B+树的实际应用(主要看主键索引),可以发现B+树中的一个节点存储的内容是:

  • § 非叶子节点:主键+指针
  • § 叶子节点:数据

 

  假设我们一行数据大小为1K,那么一页就能存16条数据,也就是一个叶子节点能存16条数据;再看非叶子节点,假设主键ID为bigint类型,那么长度为8B,指针大小在Innodb源码中为6B,一共就是14B,那么一页里就可以存储16K/14=1170个(主键+指针),那么一颗高度为2的B+树能存储的数据为:117016=18720条,一颗高度为3的B+树能存储的数据为:11701170*16=21902400(千万级条)。所以在InnoDB中B+树高度一般为1-3层,它就能满足千万级的数据存储。在查找数据时一次页的查找代表一次IO,所以通过主键索引查询通常只需要1-3次IO操作即可查找到数据。所以也就回答了我们的问题,1页=16k这么设置是比较合适的,是适用大多数的企业的,当然这个值是可以修改的,所以也能根据业务的时间情况进行调整。

 

最左前缀原则

  我们模拟数据建立一个联合索引 select *,concat(right(emp_no,1),"-",right(title,1),"-",right(from_date,2)) from employees.titles limit 10;

 

我们判断一个查询条件能不能用到索引,我们要分析这个查询条件能不能利用某个索引缩小查询范围

对于 select from employees.titles where emp_no=1是能用到索引的,因为它能利用上面的索引所有查询范围,首先和第一个节点“4-r-01”比较,1<4,所以可以直接确定结果在左子树,同理,依次按顺序进行比较,逐步可以缩小查询范围。对于select from employees.titles where title='1'是不能用到索引的,因为它不能用到上面的所以,和第一节点进行比较时,没有empno这个字段的值,不能确定到底该去左子树还是右子树继续进行查询。对于 select * from employees.titles where title='1' and emp_no=1是能用到索引,按照我们的上面的分析,先用title='1'这个条件和第一个节点进行比较,是没有结果的,但是mysql会对这个sql进行优化,优化之后会将empno=1这个条件放到第一位,从而可以利用索引。

おすすめ

転載: www.cnblogs.com/zhuminghui/p/10930389.html