如何优化查询以更快地运行?

时间:2013-02-28 13:40:18

标签: mysql sql

用户表有

id, email, password, gender, dob 

等。性别默认为null。我有另一张表user_gender,其中包含first_namegender。我的SQL查询是从User获取用户,并根据User_Genderfirst_name中选择性别。用户表非常庞大,大约有300,000多行。我正在运行下面提到的查询,但这花费了太多时间。如何优化此查询? -

select 
   count(*) 
from user u 
left outer join user_gender ug on ug.name = 
  case when locate(' ', u.name) > 0 then
     substring(u.name, 1,locate(' ', u.name))
  else
     u.name 
  end 
where 
  ug.gender != 'mf' and u.gender is null

3 个答案:

答案 0 :(得分:6)

首先我建议完全重组。 300000行开始达到“中等数据集”大小......

  • normalize表格正确
    • 不要使用存储多个单独值的列 - 尤其是名称列是一个很好的例子,而不是d。这是两列:first_name和last_name。
    • DavidB提到性别分离。这完全是胡说八道。至少,每个人都有性别......不知道,它总是NULL ...
  • 使用(最好是数字!!)ID,而不是使用数据字段(特别是那些名字)
    • 这样,如果名称改变了(可能发生IRL),你只需更新一行......
    • 两个人甚至可能有完全相同的名字......
重组后,

其次,您必须应用索引,并check your queries' execution plans确保对其进行适当优化。

答案 1 :(得分:3)

首先处理这两个表的设计将有助于您更好地解决性能问题。 性能问题发生在您的join子句中:

  

找到('',u.name)> 0然后子串(u.name,1,locate('',   u.name))否则u.name end

为User表使用主键(user_id)并在user_gender表上显示并相应地加入。

OR

由于您可能正在使用旧版数据库设计而无法添加或使用user_id字段,因此您可以使用临时first_name字段并使用您的join子句填充它

update users u set u.first_name = case when locate(' ', u.name)>0 
then substring(u.name, 1,locate(' ',> u.name)) else u.name end

在此之后,您可以将查询重写为

select count(*) from user u left outer join user_gender ug 
on ug.name=u.first_name 
where ug.gender != 'mf' and u.gender is null

这将有助于您的查询运行得更快,但我建议第一个解决方案,无论如何添加/使用主键。

答案 2 :(得分:0)

我注意到的第一件事是查询编写不正确。或者,至少,它没有做你想要的。 !=子句中的where是“撤消”左外连接。我想你想在on条款中找到它。

对于user_gender(firstname, gender)的索引,我认为这个版本应该很快运行:

select count(*) 
from (select u.*,
             (case when locate(' ', u.name) > 0 then substring(u.name, 1,locate(' ', u.name))
                   else u.name
              end) as FirstName
      from user u
     ) u
where not exists (select 1 from user_gender ug where ug.name = u.FirstName and ug.gender <> 'mf')

应该是用户表,计算名字,并检查索引以查看是否存在性别。