我开始学习MySQL,并遇到一些有关为子查询或联接建立索引的问题。我有两个创建如下的表
create table User(id integer, poster integer, PRIMARY KEY (id,poster));
insert into User(id, poster) values(1, 123);
insert into User(id, poster) values(1, 345);
insert into User(id, poster) values(2, 123);
create table Feed(id integer, poster integer, c integer, time integer, PRIMARY KEY(id), INDEX(poster),INDEX(time,c));
insert into Feed(id, poster, c,time) values(1, 123, 0, 2);
insert into Feed(id, poster, c,time) values(2, 123,1,1);
insert into Feed(id, poster, c,time) values(3, 345,2,3);
我最初尝试了一些简单的查询,例如
1. Select poster from User where id =1;
2. Select c from Feed where poster = 1;
3. Select c from Feed where poster in (1,2,3)
第三个查询的解释类似于
SIMPLE Feed NULL ALL poster NULL NULL NULL 3 100.00 Using where; Using filesort
我不确定为什么需要文件排序。但是在Feed表中添加了复合索引INDEX(time,poster,c)后,相同的查询将使用索引
这是新的创建表查询
create table Feed(id integer, poster integer, c integer, time integer, PRIMARY KEY(id),INDEX(time,poster, c));
这里是带有新的复合索引的说明输出 1 SIMPLE Feed NULL索引NULL时间15 NULL 3 50.00使用where;使用索引
我的猜测是,由于order by具有更高的优先级,并且它是最左边的索引,因此我们首先使用它。然后通过将poster添加到复合索引中,我们仍然可以使用此复合索引进行过滤,最后返回c。
然后我尝试了一些子查询
explain SELECT Feed.c from Feed where Feed.poster IN(select poster from User where id =1) order by Feed.time;
这里没什么好看的,我只是用子查询替换了硬编码的(1,2,3)。我希望看到相同的解释结果,但是我得到
1 SIMPLE User NULL ref PRIMARY,poster PRIMARY 4 const 1 100.00 Using index; Using temporary; Using filesort
1 SIMPLE Feed NULL index NULL time 15 NULL 3 33.33 Using where; Using index; Using join buffer (Block Nested Loop)
我很好奇,为什么USER表具有“使用临时”;使用文件排序。我也尝试过左连接,它也有相同的说明输出
explain SELECT Feed.c
FROM `Feed`
LEFT JOIN `User` on User.poster = Feed.poster where User.id = 1 order by Feed.time;
根据我的阅读,我们应该避免使用文件排序和temporaray文件。
如何优化索引和查询?
谢谢
答案 0 :(得分:1)
不是 不能 ,而是没有好处。
索引有点像另一个可以首先连接的表,以帮助连接到实际表。
对于您而言,扫描表的速度更快。另一种选择是使用索引来隔离基础表中哪些行是必需的 和 ,然后转到基础表以获取那些行。
如果您的表长了一百万行,那将有所不同。那么值得使用索引来减少扫描表的工作。
因此,编写一个可以创建更多随机数据的测试床,然后您就可以看到它。
或者,使用覆盖索引。其中一个包含您需要搜索的所有列以及要包含在SELECT和JOIN中的所有列。
在下面的示例中,我将(用于表格Feed) INDEX(poster)
更改为INDEX(poster, c)
。现在,如果查询计划者从索引中读取数据,它也立即知道c
的值,而无需“联接”到基础表。
create table User(id integer, poster integer, PRIMARY KEY (id,poster), INDEX(poster));
insert into User(id, poster) values(1, 123);
insert into User(id, poster) values(1, 345);
insert into User(id, poster) values(2, 123);
create table Feed(id integer, poster integer, c integer, time integer, PRIMARY KEY(id), INDEX(poster, c),INDEX(time,c));
insert into Feed(id, poster, c,time) values(1, 123, 0, 2);
insert into Feed(id, poster, c,time) values(2, 123,1,1);
insert into Feed(id, poster, c,time) values(3, 345,2,3);
现在,比较两个查询...
Select c from Feed where poster in (1,2,3)
SELECT c, time FROM feed WHERE poster IN (1,2,3)
第一个可以通过索引来回答。
第二个需要扫描整个表或在索引上查找并联接到表。由于表格太小,因此优化程序将决定只扫描整个表格,因为这样会更便宜。