MySQLはインデックスを作成するには
インデックスを作成します
#方法1:あなたがテーブルを作成 TABLEテーブル名(CREATE フィールド名1つのデータ型[整合性制約...]、 フィールド名2データタイプ[整合性制約を...]、 [UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY [インデックス名前(フィールド[(長さ)] [ASC | DESC]) ); #方法2:作成、既存のテーブルに作成索引付け CREATE [UNIQUE | FULLTEXT | SPATIAL]インデックスインデックス名 テーブル名を(フィールド名[(長さ)] [ASC | DESC]); #方法3:テーブルは、既存のテーブルにインデックスを作成するALTER [UNIQUE ADDテーブルのテーブルを変更| FULLTEXT | SPATIAL]インデックス インデックス名(フィールド名[(長さ)] [ASC | ; DESC]) テーブル名ON DROP INDEXインデックス名;:#インデックスを削除
#方式一 テーブルt1を作成します( ID int型、 名char、 年齢int型、 セックス列挙型(' 男性'、' 女性' )、 一意のキーuni_id(ID)、 インデックスix_name(名)#インデックス没有キー )。 テーブルt1(作成 のid int型、 名char、 年齢int型、 セックス列挙型(' 男性'、' 女性' )、 一意のキーuni_id(ID)、 インデックス(名前)#のインデックス没有キー )。 #方式二 T1(年齢)にインデックスix_ageを作成します。 #方式三 (性別)インデックスix_sexを追加するテーブルt1を変えます。 テーブルt1を変える指数(セックス)を追加します。 #查看 MySQLの> ショーテーブルt1を作成します。 | T1 | CREATE TABLEを`t1`( ` id`はint( 11 )は、デフォルトのNULL、 `NAME` CHAR( 1 )デフォルトNULL、 ` age`はint( 11 )は、デフォルトのNULL、 `sex`列挙(' 男性'、' 女性' )DEFAULT NULL、 UNIQUE KEY `uni_id`(` id`)、 KEY `ix_name`(` NAME`)、 KEY `ix_age`(` age`)、 KEY `ix_sex`(` sex`) )ENGINEDEFAULT = InnoDBのCHARSET = latin1の 例
テストインデックス
データ準備
#1の調製表 (表S1作成 ID int型、 名前VARCHAR( 20である)、 性別チャー( 6。 )、 メールVARCHAR(IN 50 ) ); #2が記録バッチに挿入ストアドプロシージャを作成 DELIMITER $$ #のステートメントストアドプロシージャを終了記号$$ 手順auto_insert1()を作成 BEGIN 私はint型DECLAREのデフォルトを 1。 、 しばらく(I <300万)やる S1値。INSERT INTO(I、' EVA '、' 女性'、CONCAT(' EVA '、I、" @oldboy ")); SET I = I + 1。; 終了しばらく; END $$ #$$エンド 区切り文字を; #は、セミコロンエンドシンボル修正再表示 #3は、ストアドプロシージャを参照してください。 表示は手順auto_insert1 \ Gの作成 #4コールストアドプロシージャ コールauto_insert1を();
いいえ、インデックスの前提でのテストクエリの速度
#ませインデックスません:mysqlは再びスキャンを終了する333333333に等しいレコードid、および開始からのデータのみ表、どのくらいのIO操作上のディスクブロックの数は、クエリが遅いです。この時間があるかどうかを最終的には分からない のmysql> = 333333333 WHERE ID SELECTからS1 *、 空集合(0.33秒)
すでにテーブルに存在する大量のデータの前提の下で、インデックスフィールドのセグメントに、確立が遅くなることがあります
インデックス作成が完了すると、フィールドがクエリにあるときに、クエリの速度が大幅に増加します
PS:
1. MySQLのゴーインデックステーブル探索木B +すぐにレコードが333333333存在しない検索に等しいIDの原理に従って、IO大幅に高速大幅削減
2.私たちは、あなたが占有する複数のハードディスクの空き容量を確認することができ、MySQLのテーブルにデータディレクトリを見つけることができます
3.なお、図のように。
要約:
#1フィールドは、このような選択として、検索インデックスを作成する必要があり* ID = 333 S1から 、 あなたは、インデックスを追加する必要があるID ケース#2は、テーブル内のデータをたくさん持っている、インデックスが非常に遅くなります。ハードディスクスペースを取る、構造は、クエリの後に加速 このようなインデックスIDXを作成S1(ID)上など、 ; すべてのデータテーブルをスキャンし、その後、データ項目ID、インデックス構造は、テーブルのハードディスクに格納され、作成されます。 作成したら、そのクエリは、はるかに高速になります。 #3なお:インデックスのInnoDBテーブルはs1.ibdファイルに保存され、インデックスMyISAMテーブルはtable1.MYI別のインデックスファイルを持っています MySAMインデックスとデータファイルのみが保存されている別のインデックスファイルですアドレスデータレコード。InnoDBは、テーブルデータファイル自体はB +ツリー(B木すなわちバランスTRUE)に応じて、組織のインデックス構造であり、このツリーの葉ノードデータフィールドは、完全なデータ・レコードを保持しています。キーは、データテーブルの主キーのインデックスなので、InnoDBのテーブルのデータファイル自体は、メインインデックスです。 inndobデータファイルは、主キーアグリゲーションに従い、これはInnoDBクレームテーブルは、主キーが一意のデータレコードを識別するように何がある場合(MYISAMはない)、明示的に定義されていない場合は、MySQLのシステムは自動的に、列を選択しないであろう主キーを持たなければならないのでそのようなカラムは、MySQLのInnoDBのテーブルが自動的に主キーとして隠しフィールドが生成され、このフィールドの長さは6バイト長整数型です。
あなたは正しいインデックスを打つことができる場合
インデックスミス
私たちは、インデックスは確かに、クエリをスピードアップします作成しないことをあなたは私たちがインデックスを追加する際、対象次の問題に、クエリの速度を向上させる所望の効果を達成するために、インデックスを使用したい場合
問題の範囲、または条件が明確でないこと
:これらの記号またはキーワードは条件見える>、> =、<、<=、=、と...、... BETWEEN! 、同様に
数よりも大きい、数よりも少ないです
等しくありません!=
間...と...
以下のような
差別の問題
指標として高感度なカラムを選択するために、判別式は、レコードの数の比は、我々はスキャン少ないほど、差別は一意のキーであり、フィールドの割合は省略するカウント(異なるCOL)/ COUNT(*)を示しています1、およびいくつかの州では、性別フィールドは、1つは、あなたがどんな経験を持っている、ビッグデータの差別に直面してこの比率を頼むかもしれない、おそらく0のですか?使用シナリオ異なる、この値は、我々がフィールドに参加する必要があり、一般的に、決定することは困難であるが0.1以上であることが要求される、すなわち、記録された10回の走査の平均
mysql> desc s1; +--------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+-------+ | id | int(11) | YES | MUL | NULL | | | name | varchar(20) | YES | | NULL | | | gender | char(5) | YES | | NULL | | | email | varchar(50) | YES | MUL | NULL | | +--------+-------------+------+-----+---------+-------+ rows in set (0.00 sec) mysql> drop index a on s1; Query OK, 0 rows affected (0.20 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> drop index d on s1; Query OK, 0 rows affected (0.18 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc s1; +--------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(20) | YES | | NULL | | | gender | char(5) | YES | | NULL | | | email | varchar(50) | YES | | NULL | | +--------+-------------+------+-----+---------+-------+ rows in set (0.00 sec) 先把表中的索引都删除,让我们专心研究区分度的问题
我们编写存储过程为表s1批量添加记录,name字段的值均为egon,也就是说name这个字段的区分度很低(gender字段也是一样的,我们稍后再搭理它) 回忆b+树的结构,查询的速度与树的高度成反比,要想将树的高低控制的很低,需要保证:在某一层内数据项均是按照从左到右,从小到大的顺序依次排开,即左1<左2<左3<... 而对于区分度低的字段,无法找到大小关系,因为值都是相等的,毫无疑问,还想要用b+树存放这些等值的数据,只能增加树的高度,字段的区分度越低,则树的高度越高。极端的情况,索引字段的值都一样,那么b+树几乎成了一根棍。本例中就是这种极端的情况,name字段所有的值均为'egon' #现在我们得出一个结论:为区分度低的字段建立索引,索引树的高度会很高,然而这具体会带来什么影响呢??? #1:如果条件是name='xxxx',那么肯定是可以第一时间判断出'xxxx'是不在索引树中的(因为树中所有的值均为'egon’),所以查询速度很快 #2:如果条件正好是name='egon',查询时,我们永远无 分析原因
索引列不能在条件中参与计算
索引列不能在条件中参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’)
and/or
#1、and与or的逻辑 条件1 and 条件2:所有条件都成立才算成立,但凡要有一个条件不成立则最终结果不成立 条件1 or 条件2:只要有一个条件成立则最终结果就成立 #2、and的工作原理 条件: a = 10 and b = 'xxx' and c > 3 and d =4 索引: 制作联合索引(d,a,b,c) 工作原理: 对于连续多个and:mysql会按照联合索引,从左到右的顺序找一个区分度高的索引字段(这样便可以快速锁定很小的范围),加速查询,即按照d—>a->b->c的顺序 #3、or的工作原理 条件: a = 10 or b = 'xxx' or c > 3 or d =4 索引: 制作联合索引(d,a,b,c) 工作原理: 对于连续多个or:mysql会按照条件的顺序,从左到右依次判断,即a->b->c->d
在左边条件成立但是索引字段的区分度低的情况下(name与gender均属于这种情况),会依次往右找到一个区分度高的索引字段,加速查询
经过分析,在条件为name='egon' and gender='male' and id>333 and email='xxx'的情况下,我们完全没必要为前三个条件的字段加索引,因为只能用上email字段的索引,前三个字段的索引反而会降低我们的查询效率
最左前缀匹配原则
非常重要的原则,对于组合索引mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配(指的是范围大了,有索引速度也慢),比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
其他情况
使用函数 select * from tb1 where reverse(email) = 'egon'; - 类型不一致 如果列是字符串类型,传入条件是必须用引号引起来,不然... select * from tb1 where email = 999; #排序条件为索引,则select字段必须也是索引字段,否则无法命中 - order by select name from s1 order by email desc; 当根据索引排序时候,select查询的字段如果不是索引,则速度仍然很慢 select email from s1 order by email desc; 特别的:如果对主键排序,则还是速度很快: select * from tb1 order by nid desc; - 组合索引最左前缀 如果组合索引为:(name,email) name and email -- 命中索引 name -- 命中索引 email -- 未命中索引 - count(1)或count(列)代替count(*)在mysql中没有差别了 - create index xxxx on tb(title(19)) #text类型,必须制定长度
其他注意事项
- 避免使用select * - 使用count(*) - 创建表时尽量使用 char 代替 varchar - 表的字段顺序固定长度的字段优先 - 组合索引代替多个单列索引(由于mysql中每次只能使用一个索引,所以经常使用多个条件查询时更适合使用组合索引) - 尽量使用短索引 - 使用连接(JOIN)来代替子查询(Sub-Queries) - 连表时注意条件类型需一致 - 索引散列值(重复少)不适合建索引,例:性别不适合
联合索引
联合索引
联合索引是指对表上的多个列合起来做一个索引。联合索引的创建方法与单个索引的创建方法一样,不同之处仅在于有多个索引列,如:
mysql> create table t( -> a int, -> b int, -> primary key(a), -> key idx_a_b(a,b) -> ); Query OK, 0 rows affected (0.11 sec)
覆盖索引
InnoDB存储引擎支持覆盖索引(covering index,或称索引覆盖),即从辅助索引中就可以得到查询记录,而不需要查询聚集索引中的记录。
覆盖索引 查一个数据不需要回表 select name from 表 where age = 20 不是覆盖索引 select age from 表 where age =20 是覆盖索引 select count(age) from 表 where age =20 是覆盖索引
合并索引
当我们为单独的一列创建索引的时候 如果条件是这一列,且使用正确就可以命中索引 当我们为两列分别创建单独的索引的时候 如果这两列都是条件,那么可能只能命中期中一个条件 如果这两列都是条件,那么可能会命中两个索引 - 合并索引 我们为多列直接创建联合所以 条件命中联合索引
索引总结:
1.条件一定是建立了索引的字段,如果条件使用的字段根本就没有创建索引,那么索引不生效 2.如果条件是一个范围,随着范围的值逐渐增大,那么索引能发挥的作用也越小 3.如果使用like进行模糊查询,那么使用a%的形式能命中索引,%a形式不能命中索引 4.尽量选择区分度高的字段作为索引列 5.索引列不能在条件中参与计算,也不能使用函数 6.在多个条件以and相连的时候,会优点选择区分度高的索引列来进行查询 在多个条件以or相连的时候,就是从左到右依次判断 7.制作联合索引 1.最左前缀原则 a,b,c,d 条件是a的能命中索引,条件是a,b能命中索引,a,b,c能命中,a,c.... 只要没有a就不能命中索引 如果在联合查询中,总是涉及到同一个字段,那么就在建立联合索引的时候将这个字段放在最左侧 2.联合索引 如果按照定义顺序,从左到右遇到的第一个在条件中以范围为条件的字段,索引失效 尽量将带着范围查询的字段,定义在联合索引的最后面 drop index 如果我们查询的条件总是多个列合在一起查,那么就建立联合索引 create index ind_mix on s1(id,email) select * from s1 where id = 1000000 命中索引 select * from s1 where email = 'eva1000000@oldboy' 未命中索引 但凡是创建了联合索引,那么在查询的时候,再创建顺序中从左到右的第一列必须出现在条件中 select count(*) from s1 where id = 1000000 and email = 'eva10%'; 命中索引 select count(*) from s1 where id = 1000000 and email like 'eva10%'; 可以命中索引 范围 : select * from s1 where id >3000 and email = 'eva300000@oldboy'; 不能命中索引 8.条件中涉及的字段的值必须和定义表中字段的数据类型一致,否则不能命中索引
执行计划
执行计划 看看mysql准备怎么执行这条语句 可以看到是否命中索引,计划能命中哪些,实际命中了哪些,执行的顺序,是否发生了索引合并,覆盖索引 explain select * from s1;
创建索引
#方法1:あなたがテーブルを作成 TABLEテーブル名(CREATE フィールド名1つのデータ型[整合性制約...]、 フィールド名2データタイプ[整合性制約を...]、 [UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY [インデックス名前(フィールド[(長さ)] [ASC | DESC]) ); #方法2:作成、既存のテーブルに作成索引付け CREATE [UNIQUE | FULLTEXT | SPATIAL]インデックスインデックス名 テーブル名を(フィールド名[(長さ)] [ASC | DESC]); #方法3:テーブルは、既存のテーブルにインデックスを作成するALTER [UNIQUE ADDテーブルのテーブルを変更| FULLTEXT | SPATIAL]インデックス インデックス名(フィールド名[(長さ)] [ASC | ; DESC]) テーブル名ON DROP INDEXインデックス名;:#インデックスを削除