我有3个表country_data, user_data
和topic_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
使用外键更改表格,以及我的查询。现在它适用于闪电般的速度。感谢那些帮助过的人。
答案 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_code
和user_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;