2017-12-23 9 views
1

장기적이고 무거운 데이터에서 어떤 PDO SQL 쿼리가 더 빠릅니까? 내가 그것을에서 데이터를 가져 오는 경우 테이블에서

내가 요청 된 데이터 존재 여부를 여부를 확인하고자하는 만 기록 이상이있다, 그래서 어떤 경로가 더 효율적 빠르게 입니다 그 다음 다른? idPRIMARY (INT)aid, rid 당신이 거의 측정으로, 거의 확실 동일 보여 INDEXED (INT)

+0

참고 쿼리 최적화에 대한 도움을 요청하는 모든 질문에는 쿼리의 각 테이블에 대한 'SHOW CREATE TABLE'출력이 포함되어야하므로 데이터 유형, 인덱스 및 제약 조건을 추측 할 필요가 없습니다. 그리고 많은 사람들처럼 스크린 샷처럼 텍스트로 게시하십시오. –

답변

1

두 가지 방법이 있습니다 것을 염두에

$Query = ' 
    SELECT n.id 
    FROM names n 
    INNER JOIN ages a ON n.id = a.aid 
    INNER JOIN regions r ON n.id = r.rid 
    WHERE id = :id 
'; 

$stmt->prepare($Query); 
$stmt->execute(['id' => $id]); 
if ($stmt->rowCount() == 1) { 
    $row = $stmt->fetch(); 
    ...................... 
} else { 
    exit(); 
} 

또는

$EXISTS = 'SELECT EXISTS (
    SELECT n.fname, n.lname, a.age, r.region 
    FROM names n 
    INNER JOIN ages a ON n.id = a.aid 
    INNER JOIN regions r ON n.id = r.rid 
    WHERE id = :id 
    LIMIT 1 
) 
'; 
$stmt->prepare($EXISTS); 
$stmt->execute(['id' => $id]); 
if ($stmt->fetchColumn() == 1) { 
    $stmt->prepare($Query); 
    $stmt->execute(['id' => $id]); 
    $row = $stmt->fetch(); 
    ...................... 
} else { 
    exit(); 
} 

유지 성능 차이.

SELECT n.id 
FROM names n 
INNER JOIN ages a ON n.id = a.aid 
INNER JOIN regions r ON n.id = r.rid 
WHERE id = :id 

names.id이 해당 테이블의 기본 키라고 가정합니다. 기본 키 조회는 매우 빠릅니다.

그러면 다른 두 테이블에 대한 보조 키 조회가 수행되며 해당 테이블의 다른 열에 대한 참조가 없기 때문에 인덱스 전용 액세스가됩니다.

EXPLAIN을 사용하여 MySQL의 최적화 계획을 분석하는 방법을 배워야합니다. 이것은 SQL 쿼리의 성능을 향상시키려는 경우 언제든지 연습해야하는 기술입니다.

https://dev.mysql.com/doc/refman/5.7/en/using-explain.html

mysql> explain SELECT n.id 
    ->  FROM names n 
    ->  INNER JOIN ages a ON n.id = a.aid 
    ->  INNER JOIN regions r ON n.id = r.rid 
    ->  WHERE id = 1; 

+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ 
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref | rows | filtered | Extra  | 
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ 
| 1 | SIMPLE  | n  | NULL  | const | PRIMARY  | PRIMARY | 4  | const | 1 | 100.00 | Using index | 
| 1 | SIMPLE  | a  | NULL  | ref | aid   | aid  | 5  | const | 1 | 100.00 | Using index | 
| 1 | SIMPLE  | r  | NULL  | ref | rid   | rid  | 5  | const | 1 | 100.00 | Using index | 
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ 

우리는 각 테이블 액세스 (당신이 당신의 질문에 SHOW CREATE TABLE를 제공하지 않았지만 내가 인덱스를 있으리라 믿고있어) 인덱스를 사용하고 있음을 참조하십시오.

SELECT EXISTS(...)

mysql> explain SELECT EXISTS (
    ->  SELECT n.id 
    ->  FROM names n 
    ->  INNER JOIN ages a ON n.id = a.aid 
    ->  INNER JOIN regions r ON n.id = r.rid 
    ->  WHERE id = 1 
    ->  LIMIT 1); 

+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+----------------+ 
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref | rows | filtered | Extra   | 
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+----------------+ 
| 1 | PRIMARY  | NULL | NULL  | NULL | NULL   | NULL | NULL | NULL | NULL |  NULL | No tables used | 
| 2 | SUBQUERY | n  | NULL  | const | PRIMARY  | PRIMARY | 4  | const | 1 | 100.00 | Using index | 
| 2 | SUBQUERY | a  | NULL  | ref | aid   | aid  | 5  | const | 1 | 100.00 | Using index | 
| 2 | SUBQUERY | r  | NULL  | ref | rid   | rid  | 5  | const | 1 | 100.00 | Using index | 
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+----------------+ 

하위 쿼리는 첫 번째 쿼리 최적화 계획에 동일하게 나타남에 두 번째 솔루션과 비교; 같은 방식으로 인덱스를 사용합니다. 그러나 하위 쿼리로 강등되었습니다. 아마도 큰 차이는 아니지만 한 가지 더 있습니다.

유일한 이점은 SELECT EXISTS... 쿼리가 true/false 값이있는 행 하나만 반환하도록 보장된다는 것입니다. 첫 번째 쿼리는 쿼리에서 JOIN과 일치하는 개수에 따라 0, 1 또는 여러 행이 포함 된 결과 집합을 반환 할 수 있습니다. 차이점은 성능 차이가 아닙니다. 결과 집합을 클라이언트로 전송하는 데 많은 시간이 걸리거나 많은 메모리를 사용하여 결과 집합을 클라이언트에 보관하는 경우가 아니라면 당신이 코딩하는 방식.

+0

만약'LIMIT 1'을 삭제했다면,'SELECT EXISTS -> SELECT'를 확인하는 것이 더 빠를까요? – Toleo

+0

마이크로 최적화가 끝나면 두 가지 방법으로 시도해보고 [microtime()] (http://php.net/microtime) –

+0

으로 데이터를 인덱싱해야합니까? 레코드 수를 1 백만 개로 만듭니다 '쓸모 없어? 1 백만 개의 데이터 색인을 생성하면 색인이 생성되지 않은 것처럼 많은 시간이 걸릴 것이라고 생각했기 때문에? 그리고 예상대로 예가 사용되면 모든 행의 색인이 생성됩니다. – Toleo

0

연령을 표준화하지 마십시오. 그것은 단지 공간과 시간의 낭비 일뿐입니다. age ('년'이라고 가정)은 1 바이트의 TINYINT UNSIGNED (범위 : 0..255)에 맞을 수 있으며 JOIN 조회를 피할 수 있습니다. aid은 수십억 개의 서로 다른 값을 저장할 수있는 4 바이트의 INT 인 것 같습니다. 수십억 개의 다른 연령대가 있습니까?

아마도 regions을 변경하는 것도 가치가 있습니다.

첫 번째 쿼리에서 두 JOINs은 나이와 지역에 행이 있는지 확인하지만 아무 것도하지 않습니다. 즉, 일 것입니다. 아마도입니다.

EXISTS은 한 행을 찾으면 중지합니다. 따라서 LIMIT 1은 매우 불필요합니다.

관련 문제