2011-08-11 4 views
4

꽤 간단한 저장 프로 시저를 올바르게 만드는 데 어려움을 겪고 있습니다. 다음 문서 테이블 조각 고려 : 복사 (copy-on-write)을 사용하여,MySQL의 저장된 함수를 올바르게 루프하는 방법은 무엇입니까?

id replaced_by  baseID 
1    2   0 
2    3   0 
3    0   0 

간단한 계층 테이블을. 아티클을 편집하면 현재 아티클의 replaced_by 필드가 새 복사본의 id로 설정됩니다.

나중에 article의 baseID를 저장해야하는 baseID 필드를 추가했습니다. 위 예에서 한 개의 기사 (예 : id 3)가 있습니다.

SELECT getBaseID(3); 

: 실제로 사용하여 함수를 호출 할 때까지, 그것은 간단한데

DELIMITER $$ 

CREATE FUNCTION getBaseID(articleID INT) RETURNS INT 
BEGIN 
    DECLARE x INT; 
    DECLARE y INT; 
    SET x = articleID; 
    sloop:LOOP 
     SELECT id INTO y FROM article WHERE replaced_by_articleID = x; 
     IF y IS NOT NULL THEN 
      SET x = y; 
      ITERATE sloop; 
     ELSE 
      LEAVE sloop; 
     END IF; 
    END LOOP; 
    RETURN x; 
END $$ 

DELIMITER ; 

: 그것은 baseID 1.

가 baseID를 얻으려면 것입니다, 나는 다음과 같은 저장 프로 시저를 만들었습니다 함수가 1을 반환 할 것으로 기대합니다. 두 번째 슬라이스를 취할 수도 있음을 이해하고 있습니다. 대신, 머신의 CPU는 100 % (mysqld)까지 올라간다.

REPEAT .. UNTILWHILE .. DO을 사용하여 동일한 기능을 다시 작성한 경우에도 동일한 결과가 나타납니다.

누군가 내 CPU가 루프에 들어갈 때 왜 CPU가 100 % 올라가는지 설명 할 수 있습니까?

사이드 노트 : 시간을 단순히 얻으려고합니다. 나는 PHP에서 똑같은 함수를 만들었지 만 괜찮습니다.하지만 MySQL은 약간 더 빨리 할 수 ​​있습니다. 우리는 약 1 천 8 백만 건의 기록을 살펴 봐야합니다. 내가 구할 수있는 시간은 그만한 가치가있을거야.

도움 및/또는 조언을 미리 보내 주셔서 감사합니다.


해결 SQL :

DELIMITER $$ 

CREATE FUNCTION getBaseID(articleID INT) RETURNS INT 
BEGIN 
    DECLARE x INT; 
    DECLARE y INT; 
    SET x = articleID; 
    sloop:LOOP 
     SET y = NULL; 
     SELECT id INTO y FROM article WHERE replaced_by_articleID = x; 
     IF y IS NULL THEN 
      LEAVE sloop; 
     END IF; 
     SET x = y; 
     ITERATE sloop; 
    END LOOP; 
    RETURN x; 
END $$ 

DELIMITER ; 

답변

1

mysql에서 : 쿼리에 행, 1329는 (데이터 없음) 발생하지 않는 오류 코드 경고를 반환하고,

경우 변수 값은 유지 변경되지 않음

따라서 레코드가 없을 때 무한 루프가 발생합니다 주어진 x 발견 (y은 그대로 유지) SET y = (SELECT id ....)을 대신 시도하거나 당신의 선택 문 앞에 SET y = null를 추가하면 replaced_by 컬럼에 인덱스를 누락 될 수 있습니다처럼 느낌

+0

감사합니다. 나는 INTO 비트에서 정확히 그 페이지를 읽었지 만, 변화가없는 vars로 무엇을 의미하는지 이해하지 못했습니다. – djBo

0

(그것은 루프에서 첫 번째 문이어야 함). replaced_by에 대한 색인이 없으면 반복 할 때마다 전체 표 검사를 수행합니다.

ALTER TABLE article ADD INDEX (replaced_by); 

또한 행이 있는지 확인해야합니다

DELIMITER $$ 

CREATE FUNCTION getBaseID(articleID INT) RETURNS INT 
BEGIN 
    DECLARE x INT; 
    DECLARE y INT; 
    SET x = articleID; 
    sloop:LOOP 
     SELECT COUNT(1) INTO y FROM article WHERE replaced_by = x; 
     IF y > 0 THEN 
      SELECT id INTO y FROM article WHERE replaced_by = x; 
      SET x = y; 
     ELSE 
      LEAVE sloop; 
     END IF; 
    END LOOP; 
    RETURN x; 
END $$ 

DELIMITER ; 

두 배 많은 SQL 호출을 검색하지만, 죄송합니다보다 안전한 전에.

사용해보기 !!!

+0

예, 색인을 사용할 수 있습니다. 그러나 존재하지 않는 행을 검색하는 것은 내가 테스트하고있는 것입니다. baseID를 찾았을 때 나타납니다! – djBo

관련 문제