0

我有一个如下所示的查询:

select count(test.id) from table1 
   inner join table2 on table1.id = table2.id
   where    (table2.email = 'test@gmail.com' 
   OR (table2.phone1 IS NOT NULL AND table2.phone1 in ('123456')) 
   OR (table2.phone2 IS NOT NULL AND table2.phone2 in ('1234456'))) 
   AND table2.id <> 1234 
   AND table2.created_at >= '2015-10-10' 
   AND table2.status NOT IN ('test') 
   AND table2.is_test = 'No';

我在 table2.email、table2.phone1、table2.phone2、table2.created_at 上有一个索引。这些都是单索引而不是复合索引。据我所知,(table2.email, table2.phone1, table2.phone2) 上的复合索引不起作用,因为条件是 OR 条件。我在 (table2.id, table2.created_at, table2.status, table2.is_test) 上创建了一个复合索引,但在解释查询中得到了相同的结果。解释查询如下所示

id  select_type table   type    possible_keys key     key_len ref rows Extra
 1  SIMPLE     table2   range   PRIMARY,     created_at  8        293  Using where
                                created_at,
                                email,
                                phone1,
                                phone2, 
                                com_index       
  1   SIMPLE    table1  eq_ref  PRIMARY       PRIMARY    4    id   1  Using index

这里 com_index 是我创建的复合索引。如何创建索引以加快此查询。从解释结果看,为查询选择的键是 created_at。有没有办法可以为表 2 创建复合索引?请帮我。提前致谢。

编辑:解释这个查询的生产:

+----+-------------+-------+--------+----------------------------------------------+---------+---------+----------------------+--------+-------------+
| id | select_type | table | type   | possible_keys                                | key     | key_len | ref                  | rows   | Extra       |
+----+-------------+-------+--------+----------------------------------------------+---------+---------+----------------------+--------+-------------+
|  1 | SIMPLE      | l0_   | range  | PRIMARY,created_at,email,day_phone,eve_phone | PRIMARY | 4       | NULL                 | 942156 | Using where |
|  1 | SIMPLE      | m1_   | eq_ref | PRIMARY                                      | PRIMARY | 4       | lead_platform.l0_.id |      1 | Using index |
+----+-------------+-------+--------+----------------------------------------------+---------+---------+----------------------+--------+-------------+
4

2 回答 2

2

一般来说,MySQL 不能在 3 个可能的列(电子邮件、电话 1、电话 2)上使用索引。

我怀疑您的其余条件不是很具体,并且不会在您的生产数据库上给出很好的结果(意思是,大多数项目都不是“测试”等)。

OR使用跨多个列的语句优化查询是很棘手的。

本文表明,将这样的查询拆分为多个查询UNION可以更快。在您的情况下,它将是 3 个查询组合,没有 OR 语句。这样 MySQL 可以使用email,phone1和上的索引来执行索引合并phone2

测试它,让我知道它是否在真实数据上更快。

SELECT COUNT(DISTINCT(t.id)) FROM (
    SELECT test.id FROM table1 
       INNER JOIN table2 on table1.id = table2.id
       WHERE table2.email = 'test@gmail.com' 
       AND table2.id <> 1234 
       AND table2.created_at >= '2015-10-10' 
       AND table2.status NOT IN ('test') 
       AND table2.is_test = 'No'

    UNION ALL 

    SELECT test.id FROM table1 
       INNER JOIN table2 on table1.id = table2.id
       WHERE table2.phone1 IS NOT NULL AND table2.phone1 in ('123456')
       AND table2.id <> 1234 
       AND table2.created_at >= '2015-10-10' 
       AND table2.status NOT IN ('test') 
       AND table2.is_test = 'No'

    UNION ALL   

    SELECT test.id FROM table1 
       INNER JOIN table2 on table1.id = table2.id
       WHERE table2.phone2 IS NOT NULL AND table2.phone2 in ('1234456')
       AND table2.id <> 1234 
       AND table2.created_at >= '2015-10-10' 
       AND table2.status NOT IN ('test') 
       AND table2.is_test = 'No') AS t
于 2016-11-01T21:00:46.077 回答
1

不要跨列展开一系列事物。在这种情况下,有一个电话号码表,其中包含指向 的链接table1。对于给定的 table1 类型的人,该表将有 0、1、2 甚至更多的数字。然后不需要ORUNION不需要。而是JOIN需要 a。

你有statusis_test; 这些似乎是多余的。有很多标志是没有帮助的;这些可以结合起来吗?

我不明白通过email OR phone. 似乎你会有一个或另一个价值,而不是两者兼而有之。在这种情况下,构造WHERE子句 (and JOIN),那么就不会有ORfor this 了。

毕竟,在INDEX(phone)新表和INDEX(email). table1由于电子邮件和电话可能非常有选择性,因此我不会status在索引中添加等。

于 2016-11-02T04:15:55.527 回答