使用order by时,Mysql查询运行速度非常慢

时间:2011-12-27 18:20:21

标签: mysql performance

以下查询在订购时需要30秒才能完成。没有订单,它在0.0035秒完成。我已经在字段“name”上有一个索引。字段“id”是主键。我在这张表中有400,000条记录。请帮忙,使用order by时查询有什么问题。

SELECT * 
FROM users 
WHERE name IS NOT NULL 
AND name != '' 
AND ( status IS NULL OR status = '0' ) 
order by id desc 
limit 50

更新:(最后的解决方案) 大家好,感谢您的帮助。以下是您提出的一些更新:

  1. 以下是解释的输出。

    id select_type表类型possible_keys键key_len ref rows Extra

    1 SIMPLE用户范围名称258 NULL 226009使用where;使用filesort

  2. 是的,此表中有大约20个字段。

  3. 以下是我的索引:

    Keyname Type Cardinality Field

    PRIMARY PRIMARY 418099 id 名称INDEX 411049名称

  4. 解决方案: 事实证明,具有空值的字段是原因。当where where条件中的那两个字段为NOT NULL时,它只需要.000x秒。但奇怪的是,如果我创建(status,name,id DESC)或(status,name,id)的索引,它会增加到29秒。

2 个答案:

答案 0 :(得分:5)

你肯定应该有复合索引。包含DBMS所需的所有字段的单个字段在单个查询中不能真正使用多个索引。

OR子句实际上不是索引友好的,所以如果我可以建议将status设置为 NOT NULL 。我假设NULL与零数字没有任何不同的含义。这将有助于实际使用索引。

我不知道name != ''被优化了多少。语义上相等的是name > ''(意思是它在字母表的后面),也可能节省一些CPU周期。

然后您必须决定列的显示顺序。经验法则可以是基数,即字段可能具有的值。

由此:

ALTER TABLE users ADD INDEX order1 (status, name, id DESC);

修改

您无需删除索引。 MySQL会很快选择最好的,而忽略其余的。它们仅花费UPDATE上的磁盘空间和一些CPU周期。但是如果你在任何情况下都不需要它们,你当然可以删除它们。

很长一段时间是因为您对桌子的访问速度很慢。这可能是由动态长度字段(如TEXT或BLOB)引起的。如果您不总是需要这些,您可以将它们移动到双辅助表,如:

users (id, name, status, group_id)
profile (user_id, birthdate, gender, motto, cv)

这样,基本的系统操作可以通过关于用户的受限信息来完成,并且只有在真正内容与用户相关的所有其他内容时才必须使用需要的。

<强> EDIT2

您通过指定(或更多)索引来提示MySQL使用哪个索引,如:

SELECT id, name FROM users USE INDEX (order1) WHERE name != '' and status = '0' ORDER BY id DESC

答案 1 :(得分:0)

没有解释就很难说,但很可能你也需要一个索引 “状态”列。单个表查询的缓慢几乎总是归结为执行全表扫描而不是使用索引的查询。

尝试做:

explain SELECT * 
FROM users 
WHERE name IS NOT NULL 
AND name != '' 
AND ( status IS NULL OR status = '0' ) 
order by id desc 
limit 50

并发布输出。你可能会看到它正在进行全表扫描,因为它没有状态索引。 here's some documentation on using "explain"。如果您想了解更多背景信息,请this is a nice article了解您遇到的问题。