1

我有 3 个表country_data, user_datatopic_data给定的表结构。

国家数据:

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

用户数据:

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

主题数据:

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

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

我想要的是,我需要使用给定主题的相应国家代码过滤来自每个国家的用户数量。例如,我需要查看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,即GROUP BY ud.country,执行需要 30 多秒,输出是最后一个国家代码和所有国家访问的总数。我究竟做错了什么?请帮忙。

- - 更新 - -

使用外键更改表,我的查询也是如此。现在它以闪电般的速度工作。感谢那些帮助过的人。

4

2 回答 2

2

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

JOIN另外,顺便说一句,在子句中加入 using而不是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
于 2013-09-05T06:55:27.180 回答
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;
于 2013-09-05T09:46:59.517 回答