MySQLのインデックスの最適化
最近のMySQLを学んで、このブログは、次の三つの側面からのインデックスのMySQLの理解について話します。不十分な場合は、メッセージ交換を残してください。
なぜインデックスを使用
これは、問題を解決するか、ビジネスのニーズを満たすために技術を生成しなければなりません。だから、技術のために、我々はそれを使用することを学ぶために真理を求めて、厳格な、創造の精神をする必要があります。それぞれの技術なので、社会の発展を促進する上で、無数の人々の知恵を凝縮しています。
なぜインデックスを使用してMySQLデータベースには、例として次のようなシナリオでは、著者の本に基づいて本を照会し、データベースが100,000本のデータを持っていることを前提としています。クエリの速度のインデックスを使用してインデックスを使用していないを比較するために。
データベーステーブルを作成します。
create table tb_book(id int,book_name varchar(64),author varchar(64));
アナログ100,000のデータを挿入します。
/*插入数据的方法*/ public void insertBook(Book book){ connection = DaoUtils.getConnection(); final String INSERT_BOOK = "insert into tb_book(id,book_name,author) VALUES(?,?,?)"; try { preparedStatement = connection.prepareStatement(INSERT_BOOK); preparedStatement.setInt(1,book.getId()); preparedStatement.setString(2,book.getBookName()); preparedStatement.setString(3,book.getAuthorName()); preparedStatement.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { DaoUtils.close(preparedStatement,connection); } } /*插入数据的测试*/ @Test public void testInsert(){ BookDao bookDao = new BookDao(); long startTime = System.currentTimeMillis(); int i = 0; for( i = 1;i<100000;i++){ Book book = new Book(); book.setId(i); book.setBookName("mysql技术内幕"+i); book.setAuthorName("Paul"+i); bookDao.insertBook(book); } long endTime = System.currentTimeMillis(); long time = endTime-startTime; System.out.println("插入"+i+"条数据用的时间为:"+time); } 注: 以这样的方式插入数据比较耗时,建议使用sql脚本批量查询,也就是将自动提交事物改为手动提交。
問合せは、タイトルを指定します。
インデックスを使用せずに、クエリ内の作成者の名前
/** *按照作者名查询 * @param author * @return */ public List<Book> selectByBookAuthor(String author){ final String QUERYByBook = "select * from tb_book where author='"+author+"' " ; List<Book> bookList = new ArrayList<>(); try { connection = DaoUtils.getConnection(); preparedStatement = connection.prepareStatement(QUERYByBook); resultSet=preparedStatement.executeQuery(); Book book = null; while(resultSet.next()){ book = new Book(); book.setId(resultSet.getInt("id")); book.setBookName(resultSet.getString("book_name")); book.setAuthorName(resultSet.getString("author")); bookList.add(book); } return bookList; } catch (SQLException e) { e.printStackTrace(); }finally { DaoUtils.close(resultSet,preparedStatement,connection); } return null; } /*查询的测试*/ @Test public void testBookByName(){ BookDao bookDao = new BookDao(); long startTime = System.currentTimeMillis(); List<Book> list = bookDao.selectByBookAuthor("Paul69002"); long endTime = System.currentTimeMillis(); System.out.println("未使用索引的时间:"+(endTime-startTime)); System.out.println(list.size()); }
それは995秒かかりましたプラス、インデックス、クエリのタイトル
変更テーブル構造、インデックス、および指定された長さの率を高めます。alter table tb_book add index index_author(author(16)); # 增加索引字段 /*使用索引的查询测试*/ @Test public void testBookByName(){ BookDao bookDao = new BookDao(); long startTime = System.currentTimeMillis(); List<Book> list = bookDao.selectByBookAuthor("Paul69002"); long endTime = System.currentTimeMillis(); System.out.println("使用索引的时间:"+(endTime-startTime)); }
それは927秒かかりました可視インデックスを使用すると、クエリの速度を向上させることができます。
インデックス作品:
単一のテーブルの場合:以下の表を仮定します。本を照会するには、それはそれは期待に一致するかどうかを確認するために、テーブルの各行です。テーブルが大きく、わずか数行は、検索条件に一致する場合は、テーブル全体のクエリ効率が低くなります。
上記の表に基づいて、インデックスの増加、クエリの速度が非常に速く、そのような我々は、書籍13冊の書籍の数を調べると、テーブルのスキャンを開始ようになる場合、我々は、対応する行を検索し、その値を見つけるだろうし、我々簿価は、インデックスが発注されているので、我々は、インデックスの14行を含む作品を読んだときに、値は、そう、私たちの調査のいくつかの値よりも大きくなるように数14になると、私たちは13を知ることはありませんデータの行に一致する、それは、クエリを終了します。
単一テーブルインデックス利点のために速度フルテーブルスキャンである、大幅にクエリが実行されない改善。
マルチテーブルのクエリの場合、インデックスの他の必要は、3つの索引テーブルT1、T2、T3が存在すると仮定すると、各テーブルは、一つを有し、各行は1000行を有し、これらの行は1〜1000のデジタル数を含みます、あなたは、これらのテーブルのすべての行をしたい場合。クエリに使用することができ、次の文を見つけるためにラインに等しいです
select t1.i1,t2.i2,t3.i3 from t1 inner join t2 inner join t3 where t1.i1 = t2.i2 and t2.i2= t3.i3
此查询结果应该有1000行,其中每一行有三个相等的值,如果不使用索引进新查询,根本不知道那些行包含那些值,于是我们必须尝试所有的组合,以找到与where相匹配的行。可能的组合有1000* 1000 *1000(10亿) 这比匹配数目多了100万倍。如果表的数据继续增大,查询的次数更多。这个时候就需要建立索引了,具体建立的索引的原理如下:
- 从表t1中选择一行,看该行包含什么样的值
- 利用表t2的索引,直接与表t1的值进行匹配,类似的利用表3的行直接与t1表的行相匹配
- 继续选择t1的下一行,重复前面的过程,直到持续到表t1所有的行被检查完为止。
这样查询的结果就是只对t1进行全表扫描,对表t2和t3进行索引查找.
通过以上的示例,就可以看到使用索引的好处:
- 加快查询速度
- 改进查询性能,也就是提升查询速度。
二 mysql中怎么添加索引
增加索引:
使用alter关键字添加索引
alter table tb_name add index index_name(index_columns) alter table tb_name add unique index_name(index_columns) alter table tb_name add primary key (index_columns) #主键索引,不允许为null, alter table tb_name add fulltext index_name(index_columns) alter table tb_name add spatial index_name(index_columns)
注: 其中tb_name是添加表的名称,index_name是索引的名称,可以自定义,index_columns 是添加索引的列。
限制某个索引: 就使用上述的primary key和unique ,两者的不同在于有以下两点:
- unique允许有多个空值,而primary key 不允许有空值
- 一个表中只能包含一个primary key ,而可以有多个unique索引。
2.除primary key外 ,使用create index 添加索引
crate index index_name on tb_name (index_columns);
create unique index_name on tb_name(index_columns);
create fulltext index_name on tb_name(index_columns);
create spatial index_name on tb_name(index_columns);
3.创建表时添加索引
create table tb_name(
..列定义..
index index_name(index_columns)
unique index_name(index_columns)
primary key (index_columns)
fulltext index_name(index_columns)
spatial index_name(index_columns)
);
删除索引:
删除索引的方法是 drop index 和alter table语句 ,具体语法如下:
使用drop语句
drop index index_name on tb_name; drop index 'primary' on tb_name;
使用alter来删除索引
alter table tb_name drop index_name(index_columns); alter table tb_name drop primary key;
三 怎样用好索引
索引的代价:
- 索引提高了查询速度的同时,降低了插入,删除更新值的速度。也就是说索引降低了大部分与写入相关的操作。原因就在于写入一个行不仅是写入一个数据行,还要更改索引,表的索引越多,就更改的越多,平均性能就下降的越快。
- 索引也会占用磁盘空间。增加io读写的负担。
怎么选择索引:
为用于搜索,排序或者分组的列创建索引,而对于用作输出显示的列则不用创建索引,也就是说,最佳的候选列是那些出现在where字句中的列,连接子句中的列,或者出现在order by 或者 gruop by子句中的列,那些只出现在select关键字后面输出列表里的列,则不是很好的索引候选列。
认真考虑列的基数,也就是指他所容纳所有非重复值得个数,重复值越少,使用索引优化的性能越高。例如对于记录性别的列,就每必要列出他们的索引,列的重复个数太多,基数太小。
索引短小值,尽量选择较小的数据类型。短小值可以让比的操作更快,对于更短小的值,键缓存的索引块可以容纳更多的键值。
特别是InnoDB他使用的是聚簇索引,所以主键尽量短小会带来更多的好处。索引字符串值的前缀。想要对字符串进行索引,应尽可能的指定字符串的前缀长度。具体的语法为:
create table tb_book( id int not null, book_name varchar(64), author varchar(64), index (author(10)) # 指定具有特定前缀索引的长度。 )
利用最左前缀 当创建包含n个列的复和索引时,实际上会创建n个专供Mysql使用的索引。复和索引相当于多个索引,因为索引中最左边的任意数据列集合都可用于匹配各个行,这样的集合称为“最左前缀”
.下面用一个例子进行说明:
假设有一个表,他拥有一个或者多个列的复和索引,这些列的名字分别为: country,state和city。在索引里,行的排列顺序为country/state/city,因此,行首先会自动按照country/state顺序排序,然后再按country进行排序。这意味着,即使再查询时只指定了country的值,或者只指定了country值和state的值,MYSQL也可以充分的利用索引。因此,索引可用于搜索下列几种组合
country,state , city
country ,state
country
注意:对于没有包含最左边前缀的那些搜索,如按照state或city来搜索,mysql无法使用索引。
6.不要建立过多索引,正所谓物极必反,索引亦是如此,前面提到过建立过多的索引会影响数据的写操作,而且还会占用额外的数据空间。
7.让参与的索引比较类型保持匹配。也就是再选择索引类型时,请考虑在索引列上执行的是什么类型的比较操作。不同的存储引擎使用的数据结构不同。
- 对于散列索引适用于精确查找,所以你要想精确查找某个数据的话就将表的存储引擎改为MyISAM,因为MyIsAM的默认索引类型为散列索引。
- 对于范围查找使用B树索引效果会更好,将表的结构改为InnoDB的存储引擎会更好,这是因为InnoDB的默认存储引擎为B树索引。
8.利用慢查询日志找出那些性能低劣的查询。也就是用处不大的索引。这里不做过多说明。详见《Mysql技术内幕》
参考书籍: 《MYSQL技术内幕》