2011-05-11 5 views
0

가 나는 2 (유사) 쿼리가/가능한 쿼리 문제 : Product 테이블이 비어있을 때 처음 실행에느린 MySQL의 쿼리

-- Query #1 - get all new products not in currently in the Product table 
-- Should match any products in the temp table that do not exist in the Product table 
INSERT 
    INTO `tmpProductState` (`ProductId`, `ChangedOn`, `State`) 
SELECT t.`ProductId`, t.`ProcessedOn`, \'Activated\' 
    FROM `tmpImport` t 
    LEFT JOIN `Product` p USING (`ProductId`) 
WHERE p.`ProductId` IS NULL 
    ON DUPLICATE KEY UPDATE 
     `State` = VALUES(`State`) 

-- Query #2 - get all Products that are removed from the Product table 
-- Should match any products in the Product table that do not exist in the temp table 
INSERT 
    INTO `tmpProductState` (`ProductId`, `ChangedOn`, `State`) 
SELECT p.`ProductId`, p.`LastSeenDate`, \'Deactivated\' 
    FROM `Product` p 
    LEFT JOIN `tmpImport` t USING (`ProductId`) 
WHERE t.`ProductId` IS NULL 
    ON DUPLICATE KEY UPDATE 
     `State` = VALUES(`State`) 

(1 일)를, 두 쿼리 1 초 이내에 실행, 그러나 , 제품 테이블이 14000 개 기록이있는 경우 두 번째 실행, (2 일)에 첫 번째 쿼리는 2 초 미만에서 실행하고, 두 번째 쿼리 244 초 단위로 실행됩니다. 각각의 연속적인 데이터 가져 오기는 두 번째 쿼리가 너무 오래 걸리는 이유를 난 그냥 알아낼 수 없습니다 모든 데이터가 올 것 같다 데이터베이스를 확인에 쿼리 # 2의 동일 (240~250초이다.

--- > 편집 : 느린 쿼리 로그 :이 시점에서 내가 가장 우려 무엇

# Query_time: 245.328784 Lock_time: 0.000000 Rows_sent: 0 Rows_examined: 187711973 
SET timestamp=1305151558; 

INSERT 
    INTO `tmpProductState` (`ProductId`, `ChangedOn`, `State`) 
SELECT p.`ProductId`, p.`LastSeenDate`, 'Deactivated' 
    FROM `Product` p 
    LEFT JOIN `tmpImport` t USING (`ProductId`) 
WHERE t.`ProductId` IS NULL 
    ON DUPLICATE KEY UPDATE 
     `State` = VALUES(`State`); 

: Rows_examined : 187711973 제품 테이블 크기가 ~ 14000 개 기록, 가져 오기 테이블 크기 (? 정확히 어떻게이 많은 행이 있는지 검사한다) ~ 28000 레코드이고 tmpProductState는 최대 60 레코드입니다.

---> 다른 편집 :

참여
EXPLAIN SELECT p.`ProductId` , p.`LastSeenDate` , 'Deactivated' 
FROM `Product` p 
LEFT JOIN `tmpImport` t 
USING (`ProductId`) 
WHERE t.`ProductId` IS NULL 

id select_type  table type possible_keys key  key_len  ref  rows Extra 
1 SIMPLE   p  ALL  NULL   NULL NULL   NULL 14151 
1 SIMPLE   t  index NULL   PRIMARY 100    NULL 28166 Using where; Using index; Not exists 

테이블 :

CREATE TABLE IF NOT EXISTS `tmpImport` (
    `CategoryId`    smallint(5) unsigned NOT NULL, 
    `ProcessedOn`   date DEFAULT NULL, 
    `ProductId`    varchar(32) NOT NULL, 
    `Title`     varchar(255) DEFAULT NULL, 
    `Description`   text, 
    `ActivateDate`   date DEFAULT NULL, 
    PRIMARY KEY (`CategoryId`,`ProductId`) 
) ENGINE=MyISAM DEFAULT CHARSET = UTF8 

CREATE TABLE IF NOT EXISTS `tmpProductState` (
    `ProductId` VARCHAR(32) NOT NULL, 
    `ChangedOn` DATE NOT NULL, 
    `State` ENUM(\'Activated\',\'Deactivated\'), 
    PRIMARY KEY(`ProductId`,`ChangedOn`) 
) ENGINE = Memory 

CREATE TABLE `Product` (
    `ProductId` varchar(32) NOT NULL, 
    `Title` varchar(255) DEFAULT NULL, 
    `Description` text, 
    `ActivateDate` date DEFAULT NULL, 
    `LastSeenDate` date DEFAULT NULL, 
    PRIMARY KEY (`ProductId`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 
+0

나는 (데이터를 다른 테이블로 복사하는) 왜 이런 식으로 쿼리를 실행하는지 이해하지 못했습니다.어쩌면 테이블의 구조가 당신이 필요로하는 것을 할 수있는 더 좋은 방법을 찾는데 도움이 될 수도 있음 – redShadow

+1

테이블 구조에 대한 세부 사항 ('SHOW CREATE TABLES')과'EXPLAIN SELECT ... '의 출력을 쿼리의 'SELECT'부분. –

+0

@ JamesC 임시 (세션 특정) 테이블에서 설명 부분을 수행하는 방법을 알고있는 경우이를 수행 할 수 있습니다. –

답변

0

귀하의 표는 효과적인 인덱스가없는, 정규화하지 않고, 당신은 이상한 ...입니다 합류했다.

나는 그래서 무시할 수, 당신은 테이블에서 데이터의 총 중복에 대해 아무것도 할 수 없습니다 가정합니다.

가입하려는 테이블의 열에서 데이터를 복제하는 것처럼 보이지만 가입시 해당 열을 모두 사용해야합니다. 따라서 다음과 같아야합니다.

가입하거나 필터링하는 필드에 해당하는 테이블에 색인을 추가하십시오. 복합 키를 기본 키로 사용하지 마십시오. 대신에 PK로 자동 증분 필드를 추가, 당신은 고유성을 적용해야하는 경우 고유 키가 있습니다. 두 제품 테이블과 tmpImport는 각 열의 키가 결합되어 있어야합니다.

이러한 아이디어 중 일부가 도움이되기를 바랍니다.

+0

@invertedSpear 필자와 동의하지 않는다. 내 테이블이 정규화되어있다. (매우 비정상적인 공급 업체의 데이터를 처리하는 임시 테이블을 제외하고) 합리적인 테이블에 중복이 없다. 내 문제는 복합 인덱스와 관련이 없다고 생각하지 않습니다. 또한 고유해야하는 열에 대해서는 복합 기본 키를 잘못 작성하는 것도 볼 수 없습니다. 대부분의 테이블에는 ProductId를 구성하는 기본 키와 테이블 내의 데이터에 해당하는 날짜가 있습니다. 대부분의 정보는 일별 정보이므로 –

+0

각 열의 키가 결합되어있는 한, ProductId에 의해서만 참여하면 유일하고 다른 모든 열은 다를 수 있습니다. (제목에서와 같이 임시 테이블에서 제품 테이블에있는 것과 다를 수 있으므로 다른 쿼리를 통해이를 확인하고 감사 테이블에 넣습니다.) 그래서 나는 정말로 귀하의 요점을 놓치고 있거나 귀하는 내가 성취하려는 것을 이해하는 것에서 멀리 떨어져있다. –

+0

마지막으로 187711973 행을 통해 내 두 번째 쿼리가 실행되는 이유에 대한 제안을하지 않았습니다. –

0

이에 매우 늦게 답장하지만 첫 번째 쿼리는 에서 tmpImport을 모든 레코드를지고 그들은 제품 테이블에 기본 키를 사용하여 제품에서 모든 레코드를 받고. 이것은 꽤 효율적입니다. 두 번째 쿼리는 제품에서 모든 레코드를 받고 다음 tmpImport에서하지만 tmpImport제품 ID에 어떤 인덱스의 혜택없이 일치하는 레코드를 받고있다. 따라서 잘못 실행됩니다.

는 키의 첫 번째 열이 아니므로 가입이 무시됩니다 tmpImport 테이블 (기본 키에 제품 ID제품 ID에 인덱스를 추가하면 카테고리 ID를 사용하지 않는 한 첫 번째입니다).