The initial index Mysql

mysql index optimization

Recently in learning mysql, this blog will talk about the understanding of the index mysql from the following three aspects. If insufficient, please leave a message exchanges.

Why use a index

It must produce a technology to solve a problem or to meet the needs of a business. So for technology, we should be the spirit of truth-seeking, rigorous, creative approach to learn to use it. Because each technology have condensed the wisdom of countless people, in promoting the development of society.

So why mysql database using an index, with the following scenario as an example, assume that the database has 100,000 book data, to query a book based on the author's books. In order to compare not use query speed index and using the index.

  1. Create a database table

        create table tb_book(id int,book_name varchar(64),author varchar(64));
  2. Analog insert 100,000 data:

    /*插入数据的方法*/
    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脚本批量查询,也就是将自动提交事物改为手动提交。
  3. The query specifies the title:

  • The author's name in the query without using the index

            /**
       *按照作者名查询
       * @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());
        }


    It took 995 seconds

  • Plus index, query title
    change table structure, increasing the index, and the index of the specified length.

       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));
      }


    It took 927 seconds

  • Visible using an index can improve query speed.

Index works :

For single table: Suppose a table below. To query a book, that is, each row of the table to check to see if it matches expectations. If the table is large, and only a few lines to match the search criteria, the query efficiency of the entire table will be low.

If the increase in the index on the basis of the above table, query speed will be much faster, such as we find out the number of books 13 books, and start scanning the table, then we will find the corresponding row, it will find a value, then we the book value will be number 14, the value to be greater than the value of some of our inquiry, because the index is ordered, so when we read the piece that contains 14 rows of the index, and we will never know 13 matching rows of data, then it will exit the query.

For single-table index advantage is speed full table scan, greatly improve query is not executed.

For multi-table queries, the more necessary in the index, assuming there are three index tables t1, t2, t3, each table has one, and each row has 1000 rows, these rows contain a digital number from 1 to 1000, If you want all the rows of these tables. It is equal to the line to find out the following statement can be used to query

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万倍。如果表的数据继续增大,查询的次数更多。这个时候就需要建立索引了,具体建立的索引的原理如下:

  1. 从表t1中选择一行,看该行包含什么样的值
  2. 利用表t2的索引,直接与表t1的值进行匹配,类似的利用表3的行直接与t1表的行相匹配
  3. 继续选择t1的下一行,重复前面的过程,直到持续到表t1所有的行被检查完为止。

这样查询的结果就是只对t1进行全表扫描,对表t2和t3进行索引查找.

通过以上的示例,就可以看到使用索引的好处:

  1. 加快查询速度
  2. 改进查询性能,也就是提升查询速度。

    二 mysql中怎么添加索引

增加索引:

  1. 使用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语句 ,具体语法如下:

  1. 使用drop语句

    drop index index_name on tb_name;
    drop  index 'primary' on tb_name;
  2. 使用alter来删除索引

    alter table tb_name drop index_name(index_columns);
     alter table tb_name drop primary key;

三 怎样用好索引

索引的代价:

  1. 索引提高了查询速度的同时,降低了插入,删除更新值的速度。也就是说索引降低了大部分与写入相关的操作。原因就在于写入一个行不仅是写入一个数据行,还要更改索引,表的索引越多,就更改的越多,平均性能就下降的越快。
  2. 索引也会占用磁盘空间。增加io读写的负担。

怎么选择索引:

  1. 为用于搜索,排序或者分组的列创建索引,而对于用作输出显示的列则不用创建索引,也就是说,最佳的候选列是那些出现在where字句中的列,连接子句中的列,或者出现在order by 或者 gruop by子句中的列,那些只出现在select关键字后面输出列表里的列,则不是很好的索引候选列。

  2. 认真考虑列的基数,也就是指他所容纳所有非重复值得个数,重复值越少,使用索引优化的性能越高。例如对于记录性别的列,就每必要列出他们的索引,列的重复个数太多,基数太小。

  3. 索引短小值,尽量选择较小的数据类型。短小值可以让比的操作更快,对于更短小的值,键缓存的索引块可以容纳更多的键值。
    特别是InnoDB他使用的是聚簇索引,所以主键尽量短小会带来更多的好处。

  4. 索引字符串值的前缀。想要对字符串进行索引,应尽可能的指定字符串的前缀长度。具体的语法为:

      create table tb_book(
       id  int not null,
       book_name varchar(64),
      author varchar(64),
       index (author(10))  # 指定具有特定前缀索引的长度。
       )
  5. 利用最左前缀 当创建包含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技术内幕》

Guess you like

Origin www.cnblogs.com/chentang/p/12113372.html