mysql or查询优化

上午朋友问我一条sql优化方案,因采用or全表扫描查询,导致查询速度过慢(2s多),问我有没有优化方案,具体sql如下:

set @search = 'yd12015';
SELECT `pwd_flag`,`username`,`uid`,`email`,`user_status` FROM `member` WHERE 
( 
	`user_status` >=0 and `email_status`=0 and (`username`=@search or `email`=@search or `phone`=@search)
) LIMIT 1;
逻辑意思为:查询用户表审核通过&&未锁定&&(用户名或者邮箱或者电话号码为具体字符串)的用户信息,放在自己服务器上测试,当menber表数据量达到100w级别时,查询耗时大约在1.5s左右,这是在没有并发的情况,如果存在并发,那就没得救了。得优化!

仔细思考这条sql需要得到的用户数据,发现是可以有优化方案的,首先想到的是用union查询,然后得到的sql如下:

set @search = 'yd12015';
SELECT `pwd_flag`,`username`,`uid`,`email`,`user_status` FROM `member` WHERE 
( 
	`user_status` >=0 and `email_status`=0 and `username`=@search
) 

union  

SELECT `pwd_flag`,`username`,`uid`,`email`,`user_status` FROM `member` WHERE 
( 
	`user_status` >=0 and `email_status`=0 and `email`=@search
) 

union  

SELECT `pwd_flag`,`username`,`uid`,`email`,`user_status` FROM `member` WHERE 
( 
	`user_status` >=0 and `email_status`=0 and `phone`=@search
) 
limit 1


检测查询时间,瞬间将至0.1s以下,这是妥妥的性能提升啊,可取!


第二个方案是,根据查询字符串,优化查询sql,因查询的是用户名,邮箱,电话,所以可以先判断字符串的类型,来查询对应的字段,比如,如果既不是邮箱,也不是电话,就没必要去扫描这2个字段了。如果单纯是邮箱格式,那就不可能是电话号码。


注:union的用法及一些需要注意事项:

 union:联合的意思,即把两次或多次查询结果合并起来。
 要求:两次查询的列数必须一致
 推荐:列的类型可以不一样,但推荐查询的每一列,想对应的类型以一样
 可以来自多张表的数据:多次sql语句取出的列名可以不一致,此时以第一个sql语句的列名为准。
 如果不同的语句中取出的行,有完全相同(这里表示的是每个列的值都相同),那么union会将相同的行合并,最终只保留一行。也可以这样理解,union会去掉重复的行。
如果不想去掉重复的行,可以使用union all。
 如果子句中有order by,limit,需用括号()包起来。推荐放到所有子句之后,即对最终合并的结果来排序或筛选。
如:(select * from a order by id) union (select * from b order id);
在子句中,order by 需要配合limit使用才有意义。如果不配合limit使用,会被语法分析器优化分析时去除。








你可能感兴趣的:(mysql or查询优化)