레코드가 있는지 확인하는 가장 빠른 방법


143

제목에서 알 수 있듯이 ... 레코드가 테이블에 있는지 여부를 결정하기 위해 가장 적은 오버 헤드로 가장 빠른 방법을 찾으려고합니다.

샘플 쿼리 :

SELECT COUNT(*) FROM products WHERE products.id = ?;

    vs

SELECT COUNT(products.id) FROM products WHERE products.id = ?;

    vs

SELECT products.id FROM products WHERE products.id = ?;

?가 바뀌 'TB100'었다고 가정하면 첫 번째 쿼리와 두 번째 쿼리 모두 정확히 동일한 결과 (예 : 1이 대화의 경우)를 반환합니다 . 마지막 쿼리는 'TB100'예상대로 반환 되거나 id테이블에 없는 경우 아무 것도 반환 하지 않습니다.

목적은 id테이블에 있는지 여부를 파악하는 것 입니다. 그렇지 않은 경우 프로그램은 다음에 레코드를 삽입합니다. 레코드가있는 경우 프로그램은이 질문의 범위를 벗어난 다른 프로그램 논리에 따라 레코드를 건너 뛰거나 UPDATE 쿼리를 수행합니다.

어느 것이 더 빠르고 오버 헤드가 적습니까? (이는 프로그램 실행마다 수만 번 반복되며 하루에 여러 번 실행됩니다).

(M $ 제공 JDBC 드라이버를 통해 Java에서 M $ SQL Server에 대해이 쿼리 실행)


1
데이터베이스에 따라 다를 수 있습니다. 예를 들어 Postgres에서의 계산은 다소 느립니다.
Mike Christensen

죄송합니다. jdbc 드라이버를 통해 Java가 M $ SQL과 통신 중입니다. OP를 업데이트하겠습니다.
SnakeDoc


@Nikola Markovinović :이 경우 어떻게 사용 하시겠습니까?
zerkms

5
@zerkms 상황에 따라 다릅니다. 저장 프로 시저에 있으면 if exists(select null from products where id = @id); 클라이언트에 의해 직접 호출하는 쿼리의 경우 select case when exists (...) then 1 else 0 end.
Nikola Markovinović

답변:


170

SELECT TOP 1 products.id FROM products WHERE products.id = ?; 첫 번째 레코드를 찾은 후 실행이 종료되므로 모든 제안을 능가합니다.


5
PK (또는 다른 고유 키)를 통해 검색 할 때 옵티마이 저가 자체를 고려하지 않습니까?
zerkms

3
그는 PK라고 말했지만 그렇다면 그렇다면 옵티마이 저가이를 고려할 것입니다.
Declan_K

3
@Declan_K :이 경우 내 마법 구체가 실패하고 idPK가 아닌 열 이 나타납니다. 조언에 +1하십시오.
zerkms

4
PK가 아닌 경우 해당 열에 색인이 있는지 확인하는 것이 좋습니다. 그렇지 않으면 쿼리는 더 빠른 테이블 탐색 대신 테이블 스캔을 수행해야합니다.
CD Jorgensen

4
@ nenad-zivkovic의 답변을 고려해야한다고 생각합니다.
Giulio Caccin

193

EXISTS(또는 NOT EXISTS)는 무언가 존재하는지 확인하기 위해 특별히 고안되었으므로 최선의 선택이어야합니다. 일치하는 첫 번째 행에서 중지되므로 TOP절이 필요 하지 않으며 실제로 데이터를 선택하지 않으므로 열 크기에 오버 헤드가 없습니다. 안전하게 사용할 수 없습니다 SELECT *다르지을 - 여기 SELECT 1, SELECT NULLSELECT AnyColumn... (당신도 같은 잘못된 표현을 사용 SELECT 1/0하고 휴식하지 않습니다) .

IF EXISTS (SELECT * FROM Products WHERE id = ?)
BEGIN
--do what you need if exists
END
ELSE
BEGIN
--do what needs to be done if not
END

먼저 SELECT 문을 실행 한 다음 IF EXISTS 문을 실행하지 않아도됩니다. 추가 오버 헤드가 발생하여 처리 시간이 길어 집니까?
SnakeDoc

7
@SnakeDoc No. Existsselect한 행이 발견되는 즉시 종료되는 방식으로 작동합니다 . 또한 레코드의 실제 값이 아니라 레코드가 존재한다는 사실 만 기록하므로 디스크에서 행을로드 할 필요가 없습니다 (물론 검색 기준이 색인화되었다고 가정). 오버 헤드에 관해서는 if-당신은 어쨌든이 작은 시간을 보내야 할 것입니다.
Nikola Markovinović '

1
@ NikolaMarkovinović 재미있는 포인트. 이 필드에 색인이 있는지 확실하지 않으며 새로운 SQL은 찾는 방법을 모릅니다. JDBC를 통해 Java 에서이 DB로 작업하고 있으며 데이터베이스는 콜로 어딘가에 있습니다. 각 테이블에 존재하는 필드, 해당 유형 및 FK 또는 PK를 자세히 설명하는 "데이터베이스 요약"만 제공했습니다. 이것으로도 변화가 있습니까?
SnakeDoc

3
@SnakeDoc 외래 키 및 인덱스를 포함한 테이블 구조에 대해 알아 보려면 sp_help table_name을 실행하십시오 . 이 wherther 사용하여, 많은 중 몇 행을 검색에 올 때 인덱스는 필수적 select top이나 exists, 존재하지 않으면 SQL 엔진은 테이블 스캔을 수행해야합니다. 가장 바람직한 테이블 검색 옵션입니다. 인덱스를 생성 할 권한이없는 경우 상대방의 기술 담당자에게 연락하여 인덱스가 자동으로 조정되는지 또는 인덱스 제안을 기대하는지 확인해야합니다.
Nikola Markovinović

1
@Konstantin 당신은 다음과 같은 일을 할 수 있습니다SELECT CASE WHEN EXISTS(..) THEN 1 ELSE 0 END;
Nenad Zivkovic

21

아무것도 이길 수 없습니다-

SELECT TOP 1 1 FROM products WHERE id = 'some value';

테이블에 데이터가 있는지 알 필요가 없습니다. 필요하지 않을 때는 별칭을 사용하지 마십시오.


5
그 이름에도 불구하고 id기본 키는 아닙니다. 따라서 계산 하지 않아도 수천 개의 일치하는 레코드를 모두 찾아야합니다. 앨리어싱 정보-코드가 계속 진행 중입니다. 언제 다시 가야하는지 알 수 없습니다. 앨리어싱은 바보 같은 런타임 오류를 방지하는 데 도움이됩니다. 예를 들어, 별칭필요 하지 않은 고유 한 열 이름은 다른 조인 된 테이블에서 동일한 이름의 열을 생성했기 때문에 더 이상 고유하지 않습니다.
Nikola Markovinović '

예, 당신은 절대적으로 맞습니다. 앨리어싱은 많은 도움이되지만 조인을 사용하지 않을 때 차이가 있다고 생각하지 않습니다. 그래서 필요하지 않으면 사용하지 마십시오. :) 그리고 당신은 존재를 확인하는 것에 대한 긴 토론을 여기서 찾을 수 있습니다 . :)
AgentSQL

3
내가 왜이 용어를 수락했는지 모르겠습니다 aliasing. 올바른 용어는 qualifying입니다. Alex Kuznetzov의 자세한 설명 은 다음과 같습니다 . 단일 테이블 쿼리 정보- 이제 단일 테이블 입니다. 그러나 나중에 버그가 발견되고 홍수를 막으려 고 할 때 클라이언트가 긴장하면 다른 테이블에 조인하여 오류 메시지가 나타납니다. 쉽게 수정할 수있는 메시지이지만이 땀이 나지 않는 순간에는 작은 스트로크가 발생합니다 열을 남기지 않는 것을 기억하는 오류 ...
Nikola Markovinović

1
지금은 무시할 수 없습니다. 감사!! :)
AgentSQL

15
SELECT CASE WHEN EXISTS (SELECT TOP 1 *
                         FROM dbo.[YourTable] 
                         WHERE [YourColumn] = [YourValue]) 
            THEN CAST (1 AS BIT) 
            ELSE CAST (0 AS BIT) END

이 접근 방식은 부울을 반환합니다.


1
레코드가 발견되면 Exist가 종료되므로 Top 문과 * 문을 생략하여 좀 더 빠르게 만들 수 있습니다. 다음과 같이 선택하십시오. = [YourValue]) BIT AS THEN CAST (1 AS의 BIT) ELSE CAST (0) END
스테판 Zvonar

이 제안은 이것이 SQL Server 내에 내장 된 존재 / 존재하지 않는 명령문보다 더 빠른 이유를 언급하지 않습니다. 벤치마킹이 없으면 사례 진술이 즉각적인 참 / 거짓 응답보다 더 빠른 결과를 초래할 것이라고 믿기 힘들 것입니다.
Bonez024

8

당신은 또한 사용할 수 있습니다

 If EXISTS (SELECT 1 FROM dbo.T1 WHERE T1.Name='Scot')
    BEGIN
         --<Do something>
    END 

ELSE    
     BEGIN
       --<Do something>
     END

7

아직 아무도 언급하지 않았다고 생각하지만 데이터가 변경되지 않을 것이라고 확신하는 경우 NoLock 힌트를 적용하여 읽을 때 차단되지 않도록 할 수도 있습니다.

SELECT CASE WHEN EXISTS (SELECT 1 
                     FROM dbo.[YourTable] WITH (NOLOCK)
                     WHERE [YourColumn] = [YourValue]) 
        THEN CAST (1 AS BIT) 
        ELSE CAST (0 AS BIT) END

3
SELECT COUNT(*) FROM products WHERE products.id = ?;

이것은 모든 데이터베이스에서 작동하는 상호 관계형 데이터베이스 솔루션입니다.


7
그러나 당신은 큰 테이블에 매우 느린, 모든 레코드를 통해 루프에 DB를 강제로
AMD

@amd는 왜 그런지 설명 할까?
UmNyobe

@amd 귀하의 의견은 완전히 이해됩니다. 이 쿼리는 FIND ANY보다 FIND ALL입니다.
UmNyobe

1

다음은 레코드가 데이터베이스에 존재하는지 여부를 판별하는 가장 간단하고 빠른 방법입니다. 모든 관계형 DB에서 작동하는 것이 좋습니다.

SELECT distinct 1 products.id FROM products WHERE products.id = ?;

0
create or replace procedure ex(j in number) as
i number;
begin
select id into i from student where id=j;
if i is not null then
dbms_output.put_line('exists');
end if;
exception
   when no_data_found then
        dbms_output.put_line(i||' does not exists');

end;

2
아마도 코드는 훌륭하게 작동하지만 더 많은 정보를 추가하면 더 잘 이해할 수 있습니다.
idmean

0

나는 이것을 과거에 사용했으며 무언가 존재하는지 확인하기 위해 전체 테이블 스캔이 필요하지 않습니다. 매우 빠릅니다 ...

UPDATE TableName SET column=value WHERE column=value
IF @@ROWCOUNT=0
BEGIN
     --Do work
END             

0

MySQL 또는 Oracle 배경에서이 문제를 해결하려는 경우 MySQL은 LIMIT 절을 지원하여 제한된 수의 레코드를 선택하고 Oracle은 ROWNUM을 사용합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.