2010-06-17 8 views
2

MySQL (MySQL 5.0)에 저장된 IPV4 주소와 관련된 하위 쿼리에 문제가 있습니다.MySQL 하위 쿼리의 IP 주소 번호

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 
다음 중 하나의 라인을 따라 쿼리를 할 경우 10

, 나는 결과가 내가 기대 얻을 :

말을하는 것입니다
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 

을 다른 (잘못된) 값 제공에 대한 반환됩니다. 공급자 열에 반환 된 90 % 이상의 (그러나 기이하게도 모두가 아닌) 값에 해당 IP에 대한 잘못된 공급자 정보가 포함되어 있습니다.

events.ip_address을 사용하면 하위 쿼리에서 값을 반향 출력하여 기대하는 값이 포함되어 있으며 하위 쿼리가 구문 분석 할 수 있음을 확인합니다. events.ip_address을 실제 네트워크 번호로 바꾸면 작동하지 않는 하위 쿼리에서 동적으로 사용하기 만하면됩니다.

나는 MySQL에서 하위 쿼리에 대해 근본적으로 중요하지 않은 것이 있다고 생각합니다. 필자는 이전에 MySQL에서 이와 같은 IP 주소로 작업 해 왔지만 이전에는 하위 쿼리를 사용하여 조회를 수행하지 않았습니다.

질문 :

나는 내가 원하는 출력을 얻을 수있는 방법의 예를 주셔서 감사합니다, 정말 줄 누군가가 여기 알고 있다면, 내가 무슨 일을하고있어 작동하지 않는 이유와 깨달음 그래서 나는이 실수를 다시 피할 수 있습니다.

주 :

내가 할 노력하고있어 실제 실제 사용량이 훨씬 더 복잡하다 (두 개 또는 세 개의 테이블을 조인 포함). 이것은 지나치게 복잡한 질문을 피하기 위해 단순화 된 버전입니다.

또한 ip_start & ip_end에서 사이를 사용하지 않는다는 것을 알고 있습니다. 의도적 인 것입니다 (DB의 유효 기간이 만료 될 수 있으며 이러한 경우 DB의 소유자는 거의 항상 다음 지정된 범위에 있으며 '가장 추측 '은이 맥락에서 괜찮습니다) 그러나 질문에 관련된 개선을위한 제안에 감사드립니다.

효율성은 항상 좋지만,이 경우 절대적으로 중요하지 않습니다.

+0

내 맹목적으로 조인 때문에 끔찍한 데카르트 제품 (또는 그 하위 집합)이 나타났습니다 (어쩌면 잘못된 용어이지만 여기에 테이블이 * 결합되어 있습니다 ...) – MvanGeest

답변

2

당신은이 게시물에서 살펴 보셔야합니다 :

http://jcole.us/blog/archives/2007/11/24/on-efficiently-geo-referencing-ips-with-maxmind-geoip-and-mysql-gis/

그것은 당신과 매우 유사한 쿼리에 IP를 작업을위한 몇 가지 좋은 아이디어를 가지고있다.

또 다른 한 가지 시도는 하위 쿼리 대신 저장된 함수를 사용하는 것입니다. 그러면 다음과 같이 쿼리가 간단 해집니다.

+0

+1 그 URL은 ' 내가 갖고있는 문제를 상당히 해결했지만 재미 있었다. (그리고 내가하는 일에 실제로는 관련이있다. 비록 내 질문에 그걸 간단하게하고 싶지는 않았지만). 그러나 저장된 기능에 관한 귀하의 요점은 머리에 못을 박은 것입니다. –

0

JOIN 또는 Subquery로 원하는 것을 얻을 수있는 방법이 없을 것 같습니다.

가 저장 기능을 사용 아이크 워커의 제안을 확장하기 위해

, 나는 MySQL에에 저장된 함수를 만드는 결국 다음

DELIMITER // 
DROP FUNCTION IF EXISTS get_network_provider // 
CREATE FUNCTION get_network_provider(ip_address_number INT) RETURNS VARCHAR(255) 
BEGIN 
DECLARE network_provider VARCHAR(255); 
    SELECT provider_name INTO network_provider FROM network_providers 
    WHERE ip_address_number >= network_providers.ip_start 
    AND network_providers.provider_name != "" 
    ORDER BY provider_name.ip_start DESC LIMIT 1; 
RETURN network_provider; 
END // 

설명 :

체크 빈 이름을 무시하고,> = & ORDER BY를 사용하는 것보다 ip_start를 사용하는 것 ip_start 및 ip_end는 내가 사용하고있는 두 개의 결합 된 네트워크 공급자 데이터베이스에 대한 특정 퍼지입니다. 둘 다이 방법으로 쿼리해야합니다.

이 접근법은 함수를 호출하는 쿼리가 몇 백 개의 결과를 반환하기 만하면 잘 작동합니다 (단 몇 초가 걸릴 수도 있음). 수천 개의 결과를 반환하는 쿼리에서는 2 ~ 3 분이 소요될 수 있습니다. 수만 개의 결과가있는 쿼리의 경우 (또는 그 이상) 실제 사용하기에는 너무 느립니다.

이렇게 저장된 함수 (예 : 모든 결과가 별도의 쿼리를 트리거 한 결과로 반환 됨)를 사용하면 예기치 않은 결과를 얻지 못했지만 예상보다 빠르게 성능이 저하되었습니다.

권장 사항 : 이것의 결말은 내가 데이터 구조는 단지 내 요구에 적합하지 않습니다 받아 들일 필요가 있다고했다

. 이것은 이미 친구가 나에게 지적한 것이 었습니다. 당시에 정말로 듣고 싶지 않았던 것입니다. (왜냐하면 저에게 유용했던 테이블의 다른 키로 인해 특정 network_provider DB를 사용하고 싶었 기 때문입니다. 예를 들어 지구 위치와 같은 것들).

모호한 데이터 형식을 따르는 IP 공급자 DB (또는 실제로 다른 데이터베이스)를 사용하려고하면 결국에는 적합하지 않을 수도 있으며 시도해 볼 가치가 없다고 제안 할 수 있습니다 그 (것)들과 같이 일할 것이다 함께 무언가를 자갈을 바르십시오.

최소 BETWEEN 문 (정렬 및 다른 비교 없음)을 사용하여 신뢰성있게 사용할 수 있도록 데이터를 다시 형식화해야하므로 하위 쿼리 (또는 조인)와 함께 사용할 수 있습니다. 어쨌든 모든 데이터가 엉망이 될 수도 있다는 지표.