我有一个如下所示的查询:
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)上创建了一个复合索引,但我在explain查询中得到了相同的结果。 解释查询如下所示
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 |
+----+-------------+-------+--------+----------------------------------------------+---------+---------+----------------------+--------+-------------+
答案 0 :(得分:2)
一般来说,MySQL不能在3个可能的列(电子邮件,电话1,电话2)上使用索引。
我怀疑你的其他条件不是非常具体,并且不会对你的生产数据库产生很好的结果(意思是,大多数项目都不是“测试”等)。
使用跨多个列的OR
语句优化查询非常棘手。
此article表示将此类查询拆分为多个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
答案 1 :(得分:1)
不要跨列显示一系列事物。在这种情况下,请提供一个电话号码表,其中包含返回table1
的链接。对于给定的table1类型的人,该表将具有0,1,2或甚至更多的数字。然后,不需要OR
或UNION
。相反,需要JOIN
。
您有status
和is_test
;这似乎是多余的。有很多标志是没有用的;这些可以合并吗?
我不明白email OR phone
进行查找。好像你会有一个或另一个值,而不是两者。在这种情况下,构建WHERE
子句(和JOIN
),然后就不会有OR
。
毕竟,新表格中有INDEX(phone)
,INDEX(email)
中有table1
。由于电子邮件和电话可能非常具有选择性,因此我不会将status
等添加到索引中。