优化此查询,从具有500.000个用户和一个条件的MySQL数据库中检索用户

时间:2010-08-22 09:16:45

标签: php mysql performance optimization

Suposse我有下一个 500.000行

的MySQL数据库
users
{ 
    id       - int, 
    name     - varchar(32), 
    verified - tinyint(1)
}

primary { id }
index   { verified }

我需要最后20位未经过验证的用户,所以我使用下一个查询:

SELECT * FROM users WHERE verified != 1 ORDER BY id DESC LIMIT 20

但完成后需要 1.2秒

我该如何优化它?或者在 php 中以其他方式获得相同的结果。

[编辑]

ID是主要索引, VERIFIED也是索引

[编辑2]

CREATE TABLE `users` (
  `id` int(10) unsigned NOT NULL auto_increment COMMENT 'Identificador del usuario',
  `login` varchar(32) NOT NULL COMMENT 'Login para entrar',
  `password` varchar(32) NOT NULL COMMENT 'Password para entrar',
  `email` varchar(384) NOT NULL COMMENT 'Email del usuario',
  `group_id` int(10) unsigned default NULL,
  `display_name` varchar(64) NOT NULL COMMENT 'Nombre para mostrar',
  `email_verified` tinyint(3) unsigned default '0' COMMENT 'Email verificado?',
  `banned` tinyint(3) unsigned default '0' COMMENT 'Baneado?',
  `admin` tinyint(3) unsigned default '0' COMMENT 'Es un super administrador del sitio?',
  `registered` int(10) unsigned NOT NULL COMMENT 'Fecha del registro',
  PRIMARY KEY  (`id`),
  KEY `login` (`login`),
  KEY `password` (`password`),
  KEY `email` (`email`(333)),
  KEY `group_id` (`group_id`),
  KEY `email_verified` (`email_verified`),
  KEY `banned` (`banned`),
  KEY `admin` (`admin`),
  KEY `registered` (`registered`)
) ENGINE=MyISAM AUTO_INCREMENT=500002 DEFAULT CHARSET=utf8;

[编辑3]

EXPLAIN(SELECT id FROM users WHERE email_verified != 1 ORDER BY id DESC LIMIT 20)

id: 1   
select_type: SIMPLE 
table: users    
type: range 
possible_keys: email_verified   
key: email_verified 
key_len: 2      
ref:
rows: 345195    
Extra: Using where; Using filesort

查询的个人资料

Status  Duration
(initialization)    0.0000307
Opening tables  0.000003
System lock 0.0000017
Table lock  0.0000042
init    0.000017
optimizing  0.0000077
statistics  0.000097
preparing   0.000054
executing   0.0000007
Sorting result  1.2321507
Sending data    0.000272
end 0.000004
query end   0.0000025
freeing items   0.0000099
closing tables  0.0000025
logging slow query  0.0000005

7 个答案:

答案 0 :(得分:3)

您需要一个包含idemail_verfied

的索引
KEY `foo` (`id`,`email_verified`)

然后EXPLAIN(SELECT id FROM users WHERE email_verified != 1 ORDER BY id DESC LIMIT 20)打印

+----+-------------+-------+-------+----------------+---------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys  | key     | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+----------------+---------+---------+------+------+--------------------------+
|  1 | SIMPLE      | users | index | email_verified | Index 4 | 6       | NULL |    5 | Using where; Using index |
+----+-------------+-------+-------+----------------+---------+---------+------+------+--------------------------+

特别是慢Using filesort已经消失。

答案 1 :(得分:1)

添加新索引:{verified,id}。否则你将不得不进行全表扫描。

答案 2 :(得分:0)

verified上添加索引,并改为使用以下查询:

SELECT * FROM users WHERE verified = 0 ORDER BY id DESC LIMIT 20

(假设验证可以是0或1)。

如果使用<>而不是=,MySQL将忽略索引并执行全表扫描,从而大大减慢查询速度。

答案 3 :(得分:0)

编辑:排序结果时查询速度很慢 - 如果给定订单不正确,这可能是由索引引起的。 MySQL默认为ASC排序顺序。

请参阅mysql手册:http://dev.mysql.com/doc/refman/5.0/en/create-index.html

An index_col_name specification can end with ASC or DESC. These keywords are permitted for future extensions for specifying ascending or descending index value storage. Currently, they are parsed but ignored; index values are always stored in ascending order. 

请检查此链接:

http://www.ozzu.com/programming-forum/mysql-index-cardinality-t71876.html

Why does the cardinality of an index in MySQL remain unchanged when I add a new index?

您可能需要优化索引:

OPTIMIZE TABLE users;

拥有一个带有id并经过验证的索引可能是有意义的。

你有很多索引 - 这可能会混淆mysql。

答案 4 :(得分:0)

制作另一张没有经过验证的用户的表格。这是我想要使用的最后一个解决方案。

答案 5 :(得分:0)

就像quantumSoup的答案一样,但却有一个索引(验证,id)(假设你假设id永远在增加)

SELECT * FROM users WHERE verified = 0 ORDER BY id DESC LIMIT 20

我也假设验证只是0,1

请勿使用&lt;&gt;因为这打败了指数。将“已验证”放在索引中,以便它可以进行简单的范围扫描。

答案 6 :(得分:0)

如果只有经过验证的可用值为01,请在

上创建索引
(verified, id)

并重写您的查询:

SELECT  *
FROM    users
WHERE   verified = 0
ORDER BY
        id DESC
LIMIT 20

此解决方案使用单个索引进行过滤和排序(无论数据分布如何,都能正常运行)。