如何优化我的查询?

时间:2013-09-05 06:48:36

标签: php mysql sql

我有3个表country_data, user_datatopic_data,表格结构如下所示。

country_data:

name           | code
---------------|---------------
India          | IN
United States  | US
Australia      | AU

的user_data:

user_ip        | topic_code    | country
---------------|---------------|---------------
192.168.1.1    | topic_code_1  | India
192.168.1.2    | topic_code_2  | United States
192.168.1.3    | topic_code_3  | Australia

topic_data:

name           | code
---------------|---------------
topic_1        | topic_code_1
topic_2        | topic_code_2
topic_3        | topic_code_3

我在user_data表中有大约十万(100,000)行。

我想要的是,我需要根据给定主题的相应国家/地区代码来过滤每个国家/地区的用户数。例如,我需要在每个国家/地区查看topic_2的用户数。重新输出的输出格式为

country_code   | count
---------------|---------------
IN             | 150
US             | 120
AU             | 100

现在请检查我的查询:

SELECT cd.code, COUNT(ud.country) as count 
FROM topic_data as td, user_data as ud, country_data as cd 
WHERE td.name = 'topic_1' AND td.code = ud.topic_code AND ud.country = cd.name 
GROUP BY ud.country

这个在phpmyadmin中完成执行大约需要2秒钟。在php网页中,即使在服务器中加载页面也需要15秒。通过在查询中删除组,即GROUP BY ud.country,执行时间超过30秒,输出与最后一个国家/地区代码和所有国家/地区访问的总和相关。我究竟做错了什么?请帮忙。

---- ---- UPDATE

使用外键更改表格,以及我的查询。现在它适用于闪电般的速度。感谢那些帮助过的人。

2 个答案:

答案 0 :(得分:2)

IMO的查询看起来不太糟糕。然而,数据的标准化看起来有点奇怪,例如,为什么你会在country表上有一个user_data(名称)字段,只是为了在名称上加入country来查找代码?相反,对我来说更合乎逻辑的是引用国家/地区代码(或其他索引键约束)。如果您只需要按照示例查询的代码,这也可以将联接保存到国家/地区。如果user_data是一个高容量表,您需要将其中的数据保持在最小值,以便在读取(密度)时减少IO。

另外,另外,使用JOIN而不是WHERE子句加入会提高代码的可读性,IMO:

SELECT cd.code, COUNT(ud.country) as count
FROM topic_data as td
  INNER JOIN user_data as ud
    ON td.code = ud.topic_code
  INNER JOIN country_data as cd
    ON ud.country = cd.name
WHERE td.name = 'topic_1'
GROUP BY ud.country;

要解决性能问题,请检查以下索引是否存在:

  • topic_data.name
  • 上的索引
  • 外键user_data.topic_codeuser_data.country上的索引(如果您将外键更改为user_data.country_code,则为user_data.country_code

答案 1 :(得分:0)

试试这个:

使用以下数据库结构在INNER JOIN语句中使用数字匹配可能会减少搜索时间, 所以索引你的id列表(例如主键):

**country_data**  
id|name           | code
--|---------------|---------------
1 |India          | IN
2 |United States  | US
3 |Australia      | AU

**user_data**
user_ip        | topic_id  | county_id
---------------|-----------|---------------
192.168.1.1    | 1         | 1
192.168.1.2    | 2         | 2
192.168.1.3    | 3         | 3

**topic_data**
id|name           
--|------------
1 |topic_1   
2 |topic_2
3 |topic_3 

并运行多个INNER JOIN语句,如:

SELECT cd.code, count(ud.topic_code) as count
FROM ud
INNER JOIN cd ON cd.id = ud.country
INNER JOIN td ON td.id = ud.topic_code
WHERE td.code='topic_1'
GROUP BY ud.country;