[英]MySQL: Why Select .. IN with subquery could not use index
我開始學習 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 index NULL time 15 NULL 3 50.00 Using where; 使用索引
我的猜測是因為 order by 具有更高的優先級並且它是最左邊的索引,所以我們首先使用它。 然后通過將海報添加到復合索引中,我們仍然可以使用這個復合索引做過濾,最后返回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 表有使用臨時; 使用文件排序。 我也試過 left join 它也有相同的解釋輸出
explain SELECT Feed.c
FROM `Feed`
LEFT JOIN `User` on User.poster = Feed.poster where User.id = 1 order by Feed.time;
根據我的閱讀,我們應該避免使用 filesort 和 temporaray 文件。
如何優化我的索引和查詢?
謝謝
不是不能,是沒有好處。
索引有點像另一個可以先連接的表,以幫助連接到真正的表。
在您的情況下,掃描表格會更快。 另一種方法是使用索引來隔離需要底層表中的哪些行,然后轉到底層表以獲取這些行。
如果您的表有一百萬行長,情況就會有所不同。 那么使用索引來減少掃描表的工作是值得的。
因此,編寫一個測試平台來創建更多隨機數據,然后您就可以看到它了。
或者,使用覆蓋索引。 一個包含您需要搜索的所有列以及您將包含在 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)
第一個可以僅通過索引來回答。
第二個需要掃描整個表或查找索引並連接到表。 因為表很小,優化器將決定只掃描整個表,因為這樣會更便宜。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.