Mysql 优化:有没有办法让它更快?
Mysql optimizaiton: is there any way to make this faster?
更新:
感谢大家的帮助。我会总结一下答案。
来自@Jaydee,他的回答成功地将结果减少到0.09秒,并且与LIMIT中的数字成线性关系。
select * from (select table1.id as table1_id from table1 where
table1.id < 100000 order by table1.id desc limit 1000) t1 inner join
table2 on t1.table2_id = table2.id left join table3 on t1.table3_id =
table3.id order by t1.id;
来自@Rick James,他提到这可能是 Table 2 的问题。因为我的 table 2 只有几列,所以我可以省略它,自己做连接,即使在客户端!
所以我去掉了table2,只有0.02s!
select table1
.id
as table1_id
from table1
left join table3
on table1
.table3_id
= table3
.id
where table1
.id
< 100000
order by table1
.id
desc limit 1000;
最后我发现,如果我把table2从inner join改成left join,那么所有的痛苦都消失了,就是0.03s!
select table1
.id
as table1_id
from table1
left join table2
on table1
.table2_id
= table2
.id
left join table3
on
table1
.table3_id
= table3
.id
where table1
.id
< 100000
order by table1
.id
desc limit 1000;
再次感谢您的帮助!
==============================
注意:我运行在内存有限的嵌入式服务器上(大约1G,实际上足以放入所有数据,200,000条数据)并使用SD卡作为存储。
select table1.id from table1 where id<100000 order by id desc limit
1000;
(0.01s)
select table1
.id
as table1_id
from table1
inner join table2
on table1
.table2_id
= table2
.id
where table1
.id
<
100000 order by table1
.id
desc limit 1000;
(0.40s)
select table1
.id
as table1_id
from table1
inner join table2
on table1
.table2_id
= table2
.id
where table1
.id
< 1000
order by table1
.id
desc limit 1000;
(0.01s)
select table1
.id
as table1_id
from table1
inner join table2
on table1
.table2_id
= table2
.id
left join table3
on
table1
.table3_id
= table3
.id
where table1
.id
< 100000
order by table1
.id
desc limit 1000;
(2.31s)
select table1
.id
as table1_id
from table1
inner join table2
on table1
.table2_id
= table2
.id
left join table3
on
table1
.table3_id
= table3
.id
where table1
.id
< 1000 order
by table1
.id
desc limit 1000;
(0.03s)
正如评论所建议的那样,我使用了explain,但我不太明白explain 说的是什么。请帮我检查一下。下面是最长的2.31s。
+----+-------------+----------------------+--------+-------------------------------------------------------------------+---------------------------------------+---------+---------------------------------------------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------------+--------+-------------------------------------------------------------------+---------------------------------------+---------+---------------------------------------------+-------+----------------------------------------------+
| 1 | SIMPLE | table2 | index | PRIMARY,table2_id_index | table1_id_index | 4 | NULL | 1 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | table1 | ref | PRIMARY,table1_table2_id_foreign,table1_id_index | table1_table2_id_foreign | 4 | videocap.table2.id | 27222 | Using where |
| 1 | SIMPLE | table3 | eq_ref | PRIMARY | PRIMARY | 4 | videocap.table1.table3_id | 1 | Using index |
+----+-------------+----------------------+--------+-------------------------------------------------------------------+---------------------------------------+---------+---------------------------------------------+-------+----------------------------------------------+
结果来自 desc table
table1:
+-------------------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| table2_id | int(10) unsigned | NO | MUL | NULL | |
| table3_id | int(10) unsigned | NO | MUL | 0 | |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
+-------------------------+------------------+------+-----+---------------------+----------------+
table2:
+-----------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
+-----------------+------------------+------+-----+---------------------+----------------+
table3:
+---------------------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
+---------------------------+------------------+------+-----+---------------------+----------------+
这表现如何? (糟糕。已更正)
select *
from
( SELECT table1.id as table1_id
from table1
where table1.id < 100000
order by table1.id desc
limit 1000
) t1
inner join table2 on t1.table2_id = table2.id
left join table3 on t1.table3_id = table3.id
order by t1.id;
看起来 table2 有 1 行。那是对的吗?每个 table 中有多少行?
table2 中只有 1 行,优化器似乎决定将其从一开始就移开。
在所有情况下,PRIMARY KEY(id)
,特别是如果您使用的是 InnoDB,最适合
where table1.id < $number
order by table1.id desc
然而,如果大多数 table 的 id < 100000,那么优化器可能(错误地)决定进行 table 扫描(因为它没有考虑 LIMIT
).您使用的是什么版本? 5.6 在这方面有一些改进。
请记住,查询有数百万种变体。虽然我很欣赏您尝试隔离查询的重要部分;您可能会发现将任何答案应用回 'real' 查询可能会遇到其他问题。
更新:
感谢大家的帮助。我会总结一下答案。
来自@Jaydee,他的回答成功地将结果减少到0.09秒,并且与LIMIT中的数字成线性关系。
select * from (select table1.id as table1_id from table1 where table1.id < 100000 order by table1.id desc limit 1000) t1 inner join table2 on t1.table2_id = table2.id left join table3 on t1.table3_id = table3.id order by t1.id;
来自@Rick James,他提到这可能是 Table 2 的问题。因为我的 table 2 只有几列,所以我可以省略它,自己做连接,即使在客户端!
所以我去掉了table2,只有0.02s!
select
table1
.id
astable1_id
fromtable1
left jointable3
ontable1
.table3_id
=table3
.id
wheretable1
.id
< 100000 order bytable1
.id
desc limit 1000;
最后我发现,如果我把table2从inner join改成left join,那么所有的痛苦都消失了,就是0.03s!
select
table1
.id
astable1_id
fromtable1
left jointable2
ontable1
.table2_id
=table2
.id
left jointable3
ontable1
.table3_id
=table3
.id
wheretable1
.id
< 100000 order bytable1
.id
desc limit 1000;
再次感谢您的帮助!
==============================
注意:我运行在内存有限的嵌入式服务器上(大约1G,实际上足以放入所有数据,200,000条数据)并使用SD卡作为存储。
select table1.id from table1 where id<100000 order by id desc limit 1000;
(0.01s)
select
table1
.id
astable1_id
fromtable1
inner jointable2
ontable1
.table2_id
=table2
.id
wheretable1
.id
< 100000 order bytable1
.id
desc limit 1000;
(0.40s)
select
table1
.id
astable1_id
fromtable1
inner jointable2
ontable1
.table2_id
=table2
.id
wheretable1
.id
< 1000 order bytable1
.id
desc limit 1000;
(0.01s)
select
table1
.id
astable1_id
fromtable1
inner jointable2
ontable1
.table2_id
=table2
.id
left jointable3
ontable1
.table3_id
=table3
.id
wheretable1
.id
< 100000 order bytable1
.id
desc limit 1000;
(2.31s)
select
table1
.id
astable1_id
fromtable1
inner jointable2
ontable1
.table2_id
=table2
.id
left jointable3
ontable1
.table3_id
=table3
.id
wheretable1
.id
< 1000 order bytable1
.id
desc limit 1000;
(0.03s)
正如评论所建议的那样,我使用了explain,但我不太明白explain 说的是什么。请帮我检查一下。下面是最长的2.31s。
+----+-------------+----------------------+--------+-------------------------------------------------------------------+---------------------------------------+---------+---------------------------------------------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------------+--------+-------------------------------------------------------------------+---------------------------------------+---------+---------------------------------------------+-------+----------------------------------------------+
| 1 | SIMPLE | table2 | index | PRIMARY,table2_id_index | table1_id_index | 4 | NULL | 1 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | table1 | ref | PRIMARY,table1_table2_id_foreign,table1_id_index | table1_table2_id_foreign | 4 | videocap.table2.id | 27222 | Using where |
| 1 | SIMPLE | table3 | eq_ref | PRIMARY | PRIMARY | 4 | videocap.table1.table3_id | 1 | Using index |
+----+-------------+----------------------+--------+-------------------------------------------------------------------+---------------------------------------+---------+---------------------------------------------+-------+----------------------------------------------+
结果来自 desc table
table1:
+-------------------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| table2_id | int(10) unsigned | NO | MUL | NULL | |
| table3_id | int(10) unsigned | NO | MUL | 0 | |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
+-------------------------+------------------+------+-----+---------------------+----------------+
table2:
+-----------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
+-----------------+------------------+------+-----+---------------------+----------------+
table3:
+---------------------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
+---------------------------+------------------+------+-----+---------------------+----------------+
这表现如何? (糟糕。已更正)
select *
from
( SELECT table1.id as table1_id
from table1
where table1.id < 100000
order by table1.id desc
limit 1000
) t1
inner join table2 on t1.table2_id = table2.id
left join table3 on t1.table3_id = table3.id
order by t1.id;
看起来 table2 有 1 行。那是对的吗?每个 table 中有多少行?
table2 中只有 1 行,优化器似乎决定将其从一开始就移开。
在所有情况下,PRIMARY KEY(id)
,特别是如果您使用的是 InnoDB,最适合
where table1.id < $number
order by table1.id desc
然而,如果大多数 table 的 id < 100000,那么优化器可能(错误地)决定进行 table 扫描(因为它没有考虑 LIMIT
).您使用的是什么版本? 5.6 在这方面有一些改进。
请记住,查询有数百万种变体。虽然我很欣赏您尝试隔离查询的重要部分;您可能会发现将任何答案应用回 'real' 查询可能会遇到其他问题。