如何使用NULL提高MySQL查询的性能?

时间:2016-08-17 19:37:07

标签: mysql performance innodb

下表中有几百万条记录:

CREATE TABLE `customers` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `store_id` int(10) unsigned DEFAULT NULL,
  `first_name` varchar(64) DEFAULT NULL,
  `middle_name` varchar(64) DEFAULT NULL,
  `last_name` varchar(64) DEFAULT NULL,
  `email` varchar(128) DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_store_email` (`store_id`,`email`),
  KEY `index_store_phone` (`store_id`,`phone`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

查询#1 需要约800毫秒:
SELECT COUNT(*) FROM `customers` WHERE `store_id` = 1;

查询#2 需要~1.5ms:
SELECT COUNT(*) FROM `customers` WHERE `store_id` = 1 AND `email` IS NULL;

查询#3 需要高达 5秒
SELECT COUNT(*) FROM `customers` WHERE `store_id` = 1 AND `email` IS NOT NULL;

注意:

  • 我简化了表格以询问问题,但查询完全相同。
  • 是的,我的桌子已经过优化。
  • 是的,两个字段都已建立索引,请参阅上面的创建语法。
  • 只有少数store_id,但每条记录都有一个。
  • email设置为null的客户很少。

我在这里发现了一些奇怪的事情:

  1. 查询#1最简单!只有少数可能的INT值。不应该是最快的吗?
  2. 为什么Query#3这么慢?我可以通过执行其他两个查询来减少一半的时间,并从#2中减去#1,但我不应该这样做。
  3. 对这个看似基本的问题有什么想法吗?觉得我错过了一些简单的事情。我是否在db学校上课?

2 个答案:

答案 0 :(得分:2)

有时MySQL查询解析器在决定使用哪些索引时会猜错。对于像这样的情况,索引提示可能很有用(http://dev.mysql.com/doc/refman/5.7/en/index-hints.html

强制使用索引:

SELECT * FROM table1 USE INDEX (col1_index,col2_index)
  WHERE col1=1 AND col2=2 AND col3=3;

强制使用索引,包括替换表扫描:

SELECT * FROM table1 FORCE INDEX (col1_index,col2_index)
  WHERE col1=1 AND col2=2 AND col3=3;

忽略某个索引:

SELECT * FROM table1 IGNORE INDEX (col3_index)
  WHERE col1=1 AND col2=2 AND col3=3;

要调试正在使用的索引,可以使用EXPLAIN语句:(https://dev.mysql.com/doc/refman/5.7/en/explain-output.html

EXPLAIN SELECT * FROM table1
  WHERE col1=1 AND col2=2 AND col3=3;

答案 1 :(得分:2)

仅使用(store_id)删除索引;它与另外两个索引是多余的。

这可能也不需要FORCE INDEX等等。

INDEX(store_id, email)适用于所有三个查询。