mysql 建视图索引吗_数据库建立视图索引吗

Re回4楼cyb的帖子

distinct 可以认为是group by的特例。

SELECT DISTINCT

LoginId,

SubId

FROM

TB

WHERE 1

ORDER BY Visit ASC

LIMIT 8888, 10

这个SQL等价于: select

LoginId, SubId

from TB where 1 group by

LoginId, SubId

ORDER BY Visit ASC

LIMIT 8888, 10

单纯就这条SQL而言,

ORDER BY Visit ASC 是没必要的,因为select选出的字段中没有

Visit字段,建议添加组合索引(

LoginId,

SubId

)。

假如SQL是 select

LoginId,SubId,Visit

from TB where 1 group by

LoginId, SubId

ORDER BY Visit ASC

LIMIT 8888, 10

这里可以建议组合索引(

LoginId,

SubId) 或者(

LoginId,

SubId,Visit)

Visit字段添加到索引中,仍旧避免不了排序,上面SQL的执行过程是:

1.

select

LoginId,SubId,Visit from TB where 1 group by LoginId, SubId

2.

ORDER BY Visit ASC

LIMIT 8888, 10

第一步中的group by (或者distinct)可以利用到索引(

LoginId,

SubId

)避免临时表,排序

下面是测试案例:

mysql> show create table tb\G

*************************** 1. row ***************************

Table: tb

Create Table: CREATE TABLE `tb` (

`id` int(11) DEFAULT NULL,

`LoginId` int(11) DEFAULT NULL,

`SubId` int(11) DEFAULT NULL,

`vist` int(11) DEFAULT NULL,

KEY `idx1` (`id`),

KEY `login_subId` (`LoginId`,`SubId`),

KEY `login_subId_vist` (`LoginId`,`SubId`,`vist`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8

1 row in set (0.00 sec)

mysql> explain select LoginId, SubId, vist from tb where 1 group by LoginId,SubId ;

+----+-------------+-------+-------+------------------------------+-------------+---------+------+------+-------+

| id | select_type | table | type  | possible_keys                | key         | key_len | ref  | rows | Extra |

+----+-------------+-------+-------+------------------------------+-------------+---------+------+------+-------+

|  1 | SIMPLE      | tb    | index | login_subId,login_subId_vist | login_subId | 10      | NULL |    9 | NULL  |

+----+-------------+-------+-------+------------------------------+-------------+---------+------+------+-------+

1 row in set (0.00 sec)

第二步中将步骤1中的结果集按照

Visit 字段排序,这一步的排序不可避免。

上面提到了将visit字段加入到组合索引中,是为了构建覆盖索引。避免返回到数据行去查询。

对于您提到的问题,

排序方式有多种,Visit 、ID、Count等,是不是有一种排序就要建一个“覆盖索引”?

distinct/group by的优化,关键是要利用索引,避免distinct/group by时的创建临时表,排序。

将order by的字段加入到组合索引中,目的是为了直接从二级索引字段获取到结果集,避免再去查数据行。

加了覆盖索引,索引字段变长,查询性能变好,同时也会导致占用空间、插入性能变慢。

所以是否去创建覆盖索引,还是需要依旧您的具体业务而定的。

还需要单列给Visit 、ID、Count、SubId、LoginId建索引吗?

不需要给单列

Visit 、ID、Count、SubId、LoginId建索引,这里在order by 的字段上建立索引,还是不能避免排序。

-------------------------

Re回5楼cyb的帖子

普通limit M,N的翻页写法,往往在越往后翻页的过程中速度越慢,原因

mysql会读取表中的前M+N条数据,M越大,性能就越差:

select  *  from t where sellerid=100 limit 100000,20

优化写法:

select t1.* from  t t1,

(select id from t  sellerid=100 limit 100000,20) t2

where t1.id=t2.id;

优化后的翻页写法,先查询翻页中需要的N条数据的主键id,在根据主键id

回表查询所需要的N条数据,此过程中查询N条数据的主键ID在索引中完成

这种优化的根本出发点,是减少在数据页中的扫描量。

覆盖索引,也是一种优化思路,出发点就是直接从二级索引中直接获取查询结果。

您也可以将您的业务SQL发一下,一起来看看如何优化。

-------------------------

回15楼cyb的帖子

T_Query 是一个视图对吧?

可否将T_Query的建表语句发一下呢?

-------------------------

Re回15楼cyb的帖子

SELECT DISTINCT

LoginId,

SubId

FROM

T_Query

WHERE 1

ORDER BY fenshu DESC

LIMIT 61630, 10

这条SQL从实现的功能而言,其实没必要加ORDER BY fenshu DESC 的。

distinct只能返回它的目标字段,而无法返回其它字段。 所以在SELECT DISTINCT LoginId, SubId FROM T_Query中取出的是 LoginId,SubId不重复的行。也就是说,必须LoginId和SubId都相同才会被排除。

做个测试:

mysql> select * from tb;

+------+---------+-------+------+

| id   | LoginId | SubId | vist |

+------+---------+-------+------+

|    1 |     123 |    21 |   78 |

|    2 |      43 |    71 |   78 |

|    3 |      43 |    21 |   78 |

|    2 |      43 |    71 |   78 |

|    3 |      43 |    21 |   78 |

|    2 |      43 |    71 |   78 |

|    5 |      73 |    21 |   78 |

|    2 |      55 |    67 |   78 |

|    1 |      98 |    21 |   78 |

+------+---------+-------+------+

9 rows in set (0.01 sec)

mysql> select distinct LoginId,SubId from tb ;

+---------+-------+

| LoginId | SubId |

+---------+-------+

|      43 |    21 |

|      43 |    71 |

|      55 |    67 |

|      73 |    21 |

|      98 |    21 |

|     123 |    21 |

+---------+-------+

6 rows in set (0.00 sec)

mysql> select distinct LoginId,SubId from tb where 1 order by vist;

+---------+-------+

| LoginId | SubId |

+---------+-------+

|      43 |    21 |

|      43 |    71 |

|      55 |    67 |

|      73 |    21 |

|      98 |    21 |

|     123 |    21 |

+---------+-------+

6 rows in set (0.00 sec)

这里如果建了(LoginId,SubId)即可避免distinct的创建临时表,避免排序。

mysql> explain select distinct LoginId,SubId from tb;

+----+-------------+-------+-------+------------------------------+-------------+---------+------+------+-------------+

| id | select_type | table | type  | possible_keys                | key         | key_len | ref  | rows | Extra       |

+----+-------------+-------+-------+------------------------------+-------------+---------+------+------+-------------+

|  1 | SIMPLE      | tb    | index | login_subId,login_subId_vist | login_subId | 10      | NULL |    9 | Using index |

+----+-------------+-------+-------+------------------------------+-------------+---------+------+------+-------------+

1 row in set (0.00 sec)

所以,对于您给出的SQL,我的建议是改写SQL为:

SELECT DISTINCT

LoginId,

SubId

FROM

T_Query

LIMIT 61630, 10

并添加索引( LoginId, SubId),这里一方面可以利用到索引避免临时表、排序;另一方面其实也是覆盖索引。

如果您发现去掉ORDER BY fenshu DESC 不符合您的业务需求,那么就需要考虑一下distinct的用法是否正确? select出来的结果集是否是您真实需要的。

另外需要提到一点:

您发给我的这张表,索引用法有点问题,建了很多不必要的索引。

假如建了(A),(A,B),(A,B,C)三个索引,其实(A),(A,B)都是不需要的。

-------------------------

Re回20楼华夏一剑的帖子

在您给的例子中,select id, title from tb_news where title like '%mal%'; 是可以走上索引的,并且是覆盖索引。

innodb表的二级索引上存储了主键值,上面的SQL语句只需要查询id(主键字段)和title,所以扫描二级索引字段就可以获取到结果,不要再返回主键索引读取数据了。

mysql> explain select id, title from tb_news where title like '%mal%';

+----+-------------+---------+-------+---------------+---------------+---------+------+------+--------------------------+

| id | select_type | table   | type  | possible_keys | key           | key_len | ref  | rows | Extra                    |

+----+-------------+---------+-------+---------------+---------------+---------+------+------+--------------------------+

|  1 | SIMPLE      | tb_news | index | NULL          | tb_news_title | 203     | NULL |    5 | Using where; Using index |

+----+-------------+---------+-------+---------------+---------------+---------+------+------+--------------------------+

1 row in set (0.00 sec)

而类似这种,select * from tb_news where title like '%mal%';会走全表扫描。

mysql> explain select * from tb_news where title like '%mal%';

+----+-------------+---------+------+---------------+------+---------+------+------+-------------+

| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows | Extra       |

+----+-------------+---------+------+---------------+------+---------+------+------+-------------+

|  1 | SIMPLE      | tb_news | ALL  | NULL          | NULL | NULL    | NULL |    5 | Using where |

+----+-------------+---------+------+---------------+------+---------+------+------+-------------+

1 row in set (0.00 sec)

通过覆盖索引可以获得性能上的一定优化,但是在数据量特别大,请求频繁的业务场景下不要在数据库进行模糊查询;

非得使用数据库的话 ,建议不要在生产库进行查询,可以在只读节点进行查询,避免查询造成主业务数据库的资源消耗完,导致故障;

可以使用MySQL自带的全文检索,或者一些开源的搜索引擎技术,比如sphinx.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值