我正在寻找原因和建议。 我的表大约有140万行,当我在查询后运行时,花了3分钟以上。我添加计数只是为了显示结果。我真正的查询是数不清的。
MariaDB [ams]> SELECT count(asin) FROM asins where asins.is_active = 1
and asins.title is null and asins.updated < '2018-10-28' order by sortorder,id;
+-------------+
| count(asin) |
+-------------+
| 187930 |
+-------------+
1 row in set (3 min 34.34 sec)
结构
id int(9) Primary
asin varchar(25) UNIQUE
is_active int(1) Index
sortorder int(9) Index
如果您需要更多信息,请告诉我。 预先感谢。
编辑 用EXPLAIN查询
MariaDB [ams]>从asins中解释asin,其中asins.is_active = 1且asins.title为null且asins.updated <'2018-10-28'按sortorder,id;
答案 0 :(得分:2)
数据库正在扫描所有行以回答查询。我想你的桌子很大。
对于此查询,ORDER BY
是不必要的(但它不会对性能产生影响:
SELECT count(asin)
FROM asins
WHERE asins.is_active = 1 AND
asins.title is null AND
asins.updated < '2018-10-28' ;
然后您要在(is_active, title, updated)
上建立索引。
答案 1 :(得分:1)
好像您在is_active上有一个索引并已更新。因此将要扫描该索引(就像表扫描一样,读取索引中的每个记录),但是由于title不在索引中,因此将有第二个操作在表中查找title。您可以将其视为索引和表之间的联接。如果索引中的大多数记录都符合您的条件,则联接将涉及表中的大多数数据。大型联接很慢。
如果针对索引的条件将导致返回大量记录,那么使用全表扫描可能会更好。
有关强制全表扫描的方法,请参见https://dba.stackexchange.com/questions/110707/how-can-i-force-mysql-to-ignore-all-indexes。尝试一下,看看您的查询是否更快。
答案 2 :(得分:1)
尝试以下方法:
INDEX(is_active, updated),
INDEX(is_active, sortorder, id)
请提供SHOW CREATE TABLE
。
使用这些索引中的第一个,将完成一些过滤,但是随后仍然需要对结果进行排序。
使用第二个索引,优化器可以选择对唯一的=
列进行过滤,然后通过启动ORDER BY
来避免排序。这样做的风险是,它仍然必须行很多行,以至于避免进行排序是不值得的。
is_active = 1
占表的百分之几?空title
为空的百分比是多少?该日期范围内的百分比是多少?
答案 3 :(得分:0)
创建复合索引时,其中一部分是基于范围的,则需要首先基于范围的部分。
所以尝试索引(已更新,is_active,标题)
这种更新方式成为前缀,可以在范围查询中使用。