2013-03-08 2 views
1

나는 일정 기간 동안 활성화되지 않은 고객에게 프로모션 이메일을 보낼 수 있도록 MySQL 데이터베이스에서 데이터를 수집해야하지만 등록한 적이없는 사용자 만 데이터를 수집해야합니다. 그들의 프로모션은 우리를 가리 킵니다. 데이터베이스가 상당히 커서 고객이 50,000 명이 넘고 포인트를 등록하지 않은 고객의 customer_id를 확인하는 쿼리는 한 시간 만 처리해야합니다. 그래서 나는 주어진 시간 내에 로그인하지 않은 고객에게 그것을 좁히고 그 고객 ID 만 검색하면 더 빠를 것이라고 생각했습니다. 그러나 두 개의 쿼리를 결합하려는 시도는 "Operand에 1 개의 열이 있어야합니다."라는 오류를 반환하는 전체 실패였습니다.큰 결과를 반환하는 결합 된 SQL 쿼리

내가 쿼리에서받는 데 필요한 데이터를 얻는 것이 가능합니까?

1 시간 소요

첫 번째 쿼리 :

SELECT ci.customers_info_date_of_last_logon, ci.customers_info_id, c.customers_email_address, c.customers_lastname, c.customers_firstname 
FROM customers c, customers_info ci 
WHERE c.customers_id = ci.customers_info_id 
GROUP BY c.customers_email_address 
HAVING max(ci.customers_info_date_of_last_logon) <= subdate(now(),INTERVAL 30 DAY) 
ORDER BY c.customers_lastname, c.customers_firstname ASC 

내가 시도하고, 그들을 결합하는 데 실패 방법 :

SELECT c.customers_id 
FROM customers c 
LEFT JOIN codes_redeem_history pc 
ON pc.customer_id=c.customers_id 
WHERE pc.customer_id IS NULL 
AND c.customers_id 
IN 
(Select ci.customers_info_date_of_last_logon, ci.customers_info_id, c.customers_email_address, c.customers_lastname, c.customers_firstname 
FROM customers c, customers_info ci 
WHERE c.customers_id = ci.customers_info_id 
GROUP BY c.customers_email_address 
HAVING max(ci.customers_info_date_of_last_logon) <= subdate(now(),INTERVAL 30 DAY) 
ORDER BY c.customers_lastname, c.customers_firstname ASC) 

I를 주어진 시간 내에 고객을위한

SELECT c.customers_id 
FROM customers c 
LEFT JOIN codes_redeem_history pc 
ON pc.customer_id=c.customers_id 
WHERE pc.customer_id IS NULL 

두 번째 쿼리를 오류 메시지에서 복잡한 쿼리가 IN (SELECT)에 허용되지 않음을 알 수 있습니다. 질의의 일부분이지만 재 배열하는 방법이나 실현 가능성이있는 경우 손실이 있습니다.

당신의 조언은 무엇입니까? SQL Gurus? 요구 사항의 약간의 변화에 ​​따라

덕분에

, 나는이에 좀 더 도움으로 할 수 있습니다.

이전 답변에서 나는 30 일에 고정되기보다는 시간 범위를 선택할 수 있도록 쿼리를 약간 변경하려고했습니다. HAVING MAX (ci.customers_info_date_of_last_logon)> = "". $ ndate "를 사용했습니다. $ ndate는 필요한 날짜를 저장하는 var입니다. 분명히 날짜가 30 일과 같지 않기 때문에 작동하지 않았습니다. 나는 최대치 대신에 WHERE 조건을 사용할 수있는 것 같지 않습니다. 어떤 해결책?

+0

IN() 함수의 하위 쿼리는 여러 열을 반환합니다. 하나의 열만 리턴하도록 수정해야합니다. –

+0

쿼리를 "설명하는"것이 좋을까요 ... 첫 번째 쿼리가 너무 오래 걸리는 것은 이상한 일입니다. 인덱스가 있습니까? – m4573r

+0

@ m4573r 아니요, 색인이없고 codes_redeem_history 테이블에 400210 개의 행이 들어 있으므로 매우 느립니다. –

답변

2

첫 번째 쿼리를 완료하는 데 시간이 너무 오래 걸리는 이유는, 당신이 그들의 관계를, 다음 줄을 실행하여 테이블을 변경을 정의하는 컬럼에 인덱스를 부족하기 때문에 내가, 그것을 거의 확신

입니다
ALTER TABLE codes_redeem_history ADD INDEX (customer_id); 
ALTER TABLE customers ADD INDEX (customers_id); 
ALTER TABLE customers_info ADD INDEX (customers_info_id); 

전체 쿼리,

SELECT c.customers_id 
FROM customers c 
     LEFT JOIN codes_redeem_history pc 
     ON pc.customer_id=c.customers_id 
     LEFT JOIN 
     (
      Select c.customers_id 
      FROM customers c 
        INNER JOIN customers_info ci 
         ON c.customers_id = ci.customers_info_id 
      GROUP BY c.customers_email_address 
      HAVING MAX(ci.customers_info_date_of_last_logon) <= subdate(now(),INTERVAL 30 DAY) 
     ) d ON c.customers_id = d.customers_id 
WHERE pc.customer_id IS NULL AND 
     d.customers_id IS NOT NULL 

UPDATE 1

SELECT c.customers_id 
FROM customers c 
     INNER JOIN customers_info ci 
      ON c.customers_id = ci.customers_info_id 
     LEFT JOIN codes_redeem_history pc 
      ON c.customers_id = pc.customer_id 
WHERE pc.customer_id IS NULL 
GROUP BY c.customers_email_address 
HAVING MAX(ci.customers_info_date_of_last_logon) <= subdate(now(),INTERVAL 30 DAY) 
+0

당신은 절대적인 다이아몬드입니다. INDEX를 추가하면 쿼리의 첫 번째 부분을 실행하는 데 0.0006 초의 큰 차이가있었습니다!하지만 전체 SQL은 "올바른 구문을 사용하기 위해 MySQL 서버 버전에 해당하는 설명서를 확인합니다."d ON c.customers_id = d.customers_id pc.customer_id가 NULL이고 '13 행에 있습니다.' –

+0

오, 죄송합니다. 유형이 잘못되었습니다. ')'subdate (지금(), INTERVAL 30 DAY)' –

+0

두 개의 검색어를 뒤집을 수 있습니까? pc.customer_id 원래 두 번째 쿼리의 결과를 NULL 부분을 필터링하는 경우 주위 이제 선택이 LEFT c를 고객 을 c.customers_id 있도록 pc.customer_id = c.customers_id ON codes_redeem_history PC 가입하세요? –

관련 문제