【发布时间】:2010-06-17 14:12:43
【问题描述】:
我在涉及存储在 MySQL (MySQL 5.0) 中的 IPV4 地址的子查询时遇到问题。
IP 地址存储在两个表中,均采用网络编号格式 - 例如MySQL 的 INET_ATON() 输出的格式。第一个表('events')包含许多行,其中包含与其关联的 IP 地址,第二个表('network_providers')包含给定网络块的提供者信息列表。
事件表(~4,000,000 行):
event_id (int)
event_name (varchar)
ip_address (unsigned int)
network_providers 表(约 60,000 行):
ip_start (unsigned int)
ip_end (unsigned int)
provider_name (varchar)
针对我遇到的问题进行了简化,目标是按照以下方式创建导出:
event_id,event_name,ip_address,provider_name
如果按照以下任一方式进行查询,我会得到我期望的结果:
SELECT provider_name FROM network_providers WHERE INET_ATON('192.168.0.1') >= network_providers.ip_start ORDER BY network_providers.ip_start DESC LIMIT 1
SELECT provider_name FROM network_providers WHERE 3232235521 >= network_providers.ip_start ORDER BY network_providers.ip_start DESC LIMIT 1
也就是说,对于我查找的任何 IP,它都会返回正确的 provider_name(当然,我在查询中并没有真正使用 192.168.0.1)。
但是,当执行与子查询相同的查询时,按照以下方式,它不会产生我期望的结果:
SELECT
events.event_id,
events.event_name,
(SELECT provider_name FROM network_providers
WHERE events.ip_address >= network_providers.ip_start
ORDER BY network_providers.ip_start DESC LIMIT 1) as provider
FROM events
返回的是 provider 的不同(不正确)值。 provider 列中返回的超过 90%(但奇怪的是不是全部)的值包含该 IP 的错误提供商信息。
在子查询中使用 events.ip_address 只是为了回显该值,以确认它包含我期望的值并且子查询可以解析它。用实际的网络号替换 events.ip_address 也可以,只是在子查询中以这种对我不起作用的方式动态使用它。
我怀疑问题在于 MySQL 中的子查询有一些基本而重要的东西,我不明白。我以前在 MySQL 中使用过类似的 IP 地址,但以前没有使用子查询对它们进行过查找。
问题:
我非常感谢我如何获得我想要的输出的一个例子,如果有人知道,一些关于为什么我正在做的事情不起作用的启示,这样我就可以避免再次犯这个错误。
注意事项:
我尝试做的实际实际使用要复杂得多(涉及连接两个或三个表)。这是一个简化版本,以避免问题过于复杂。
此外,我知道我没有在 ip_start 和 ip_end 上使用 between - 这是故意的(数据库可能已过时,在这种情况下,数据库中的所有者几乎总是在下一个指定范围内并且“最佳猜测” ' 在这种情况下很好)但是我很感谢与该问题相关的任何改进建议。
效率总是很好,但在这种情况下绝对不是必需的 - 任何帮助表示赞赏。
【问题讨论】:
-
我认为由于您的隐式连接(可能这是错误的术语,但表 正在 在这里连接,所以出现了可怕的笛卡尔积(或其子集)。 ..)