SQL : 레코드가 있는지 올바르게 확인하는 방법


207

SQL Tuning 관련 문서를 읽는 동안 다음을 발견했습니다.

SELECT COUNT(*) :

  • 행 수를 계산합니다.
  • 종종 레코드의 존재를 확인하는 데 잘못 사용됩니다.

SELECT COUNT(*)정말 나쁜?

기록이 있는지 확인하는 올바른 방법은 무엇입니까?

답변:


252

다음 중 하나를 사용하는 것이 좋습니다.

-- Method 1.
SELECT 1
FROM table_name
WHERE unique_key = value;

-- Method 2.
SELECT COUNT(1)
FROM table_name
WHERE unique_key = value;

첫 번째 대안은 결과 또는 하나의 결과를 제공하지 않아야하며, 두 번째 개수는 0 또는 1이어야합니다.

사용중인 문서는 몇 살입니까? 좋은 조언을 읽었지만 최근 RDBMS의 대부분의 쿼리 최적화 프로그램은 SELECT COUNT(*)어쨌든 최적화 하므로 이론과 오래된 데이터베이스에는 차이가 있지만 실제로는 차이를 느끼지 않아야합니다.


1
나는 "key = value"절을 사용하여 "고유 키"를 의도했지만 여전히 내 대답 뒤에 있다는 것을 명확히 할 것입니다.
Martin Schapendonk

1
확인. 그 전제로 쿼리는 실제로 하나 또는 제로 레코드를 반환합니다. 그러나 질문은 고유 한 열로 제한되지 않습니다. 또한 : 두 번째 쿼리 count (1)는 실제 POV의 count (*)와 같습니다.
Martin Ba

1
문제는 "A 레코드의 존재를 확인하는 올바른 방법은 무엇입니까"라고 말합니다. 나는 1 레코드와 같이 그것을 단수로 해석했다. count (*)와 count (1)의 차이점은 이미 내 대답으로 덮여 있습니다. count (1)은 특정 RDBMS 구현에 의존하지 않기 때문에 선호합니다.
Martin Schapendonk

192

Count 함수를 전혀 사용하지 않는 것이 좋습니다.

IF [NOT] EXISTS ( SELECT 1 FROM MyTable WHERE ... )
     <do smth>

예를 들어 데이터베이스에 사용자를 삽입하기 전에 사용자가 있는지 확인하려는 경우 쿼리는 다음과 같습니다.

IF NOT EXISTS ( SELECT 1 FROM Users WHERE FirstName = 'John' AND LastName = 'Smith' )
BEGIN
    INSERT INTO Users (FirstName, LastName) VALUES ('John', 'Smith')
END

일반적으로 우리는 무언가를 원할 때 그것을 사용합니다 (확인). 그러면 당신의 대답은 더 완전합니다.
Abner Escócio

언급 한 것은 T-SQL을 사용함으로써
Bronek

20

당신이 사용할 수있는:

SELECT 1 FROM MyTable WHERE <MyCondition>

조건과 일치하는 레코드가 없으면 결과 레코드 세트가 비어 있습니다.


TOP 1을 의미 했습니까? -> (<MyCondition>에서 MyTable에서 TOP 1 선택)
Jacob

6
아니요, 정확히 "1"을 의미했습니다
Cătălin Pitiș

1
쿼리 옵티마이 저가 나머지 데이터 세트를 읽거나 필요로하지 않을 수 있도록하기 위해 SELECT TOP 1 1 FROM ... WHERE ...를 명시해야합니다 (또는 RDBS에 적절한 쿼리 힌트 사용)
eFloh

3
Exists 연산자 자체는 최소한의 정보 만 검색하려고하므로 TOP 1을 추가하면 쿼리 크기에 5자를 추가하는 것 외에는 아무 것도 수행하지 않습니다. - sqlservercentral.com/blogs/sqlinthewild/2011/04/05/...
AquaAlex

13

다른 답변은 꽤 좋지만 불필요한 행을 확인하지 못하도록 추가 LIMIT 1(또는 이에 상응하는 )를 사용하는 것이 좋습니다.


3
"존재 확인"쿼리가 둘 이상의 행을 반환하면 결과 수를 제한하는 대신 WHERE 절을 다시 확인하는 것이 더 유용하다고 생각합니다.
Martin Schapendonk

2
나는 한계가 SQL 서버에서 오라클이 아닌 사용됩니다 생각
샨 굽타을

7
나는 그들이 합법적으로 여러 행이 될 수있는 경우를 고려하고 있습니다. 질문은 "이 조건을 만족시키는 (하나 이상) 행이 있습니까?"입니다. 이 경우, 하나만보고 싶지는 않습니다.
JesseW

1
@Shantanu-나는 이것이 다른 양식을 설명하는 (매우 관통하는) en.wikipedia 기사에 링크 된 이유입니다.
JesseW

11
SELECT COUNT(1) FROM MyTable WHERE ...

모든 레코드를 통해 반복됩니다. 이것이 레코드 존재에 사용하기 어려운 이유입니다.

나는 사용할 것이다

SELECT TOP 1 * FROM MyTable WHERE ...

1 개의 레코드를 찾은 후 루프가 종료됩니다.


의 경우 SELECT TOP 1실제로 하나를 발견 한 후 종료됩니다 아니면 모든 TOP 어느 하나라고 할 수 찾기 위해 계속합니까?
Eirik H

3
추신 : 내가 항상 확인IF EXISTS (SELECT TOP 1 1 FROM ... WHERE ..)
Eirik H

Star 연산자는 DBMS가 조인 조건에 필요한 인덱스 대신 클러스터 된 인덱스에 액세스하도록합니다. 결과적으로 상수 valua를 사용하는 것이 좋습니다. 예를 들어 top 1 1 ...을 선택하면 조건이 일치하는지 여부에 따라 1 또는 DB-Null을 반환합니다.
eFloh

좋네요 나는 첫 번째를 좋아한다.
isxaker

10

당신이 사용할 수있는:

SELECT COUNT(1) FROM MyTable WHERE ... 

또는

WHERE [NOT] EXISTS 
( SELECT 1 FROM MyTable WHERE ... )

이보다 더 효율적입니다 SELECT *모든 필드가 아닌 각 행에 대해 단순히 값 1을 선택하기 때문에 입니다.

COUNT (*)와 COUNT (열 이름) 사이에는 미묘한 차이가 있습니다.

  • COUNT(*) null을 포함하여 모든 행을 계산합니다.
  • COUNT(column name)Null이 아닌 열 이름 만 계산합니다.

2
DBMS가 어떻게 든 모든 열을 검사한다고 잘못 가정하고 있습니다. 사이의 성능 차이 count(1)count(*)는 가장 뇌사 DBMS 다를 수 있습니다.
paxdiablo

2
아니, 난 것을 말하고 당신이 당신이 더 효율적일 수 있습니다 진술 할 때 실제로 구현 세부 정보에 의존하고 있습니다. 최상의 성능을 얻으려면 대표 데이터를 사용하여 특정 구현에 맞게 프로파일 링하거나 완전히 잊어 버리십시오. 다른 것은 잠재적으로 오해의 소지가 있으며 DB2에서 MySQL로 이동할 때 (예를 들어) 급격히 변할 수 있습니다.
paxdiablo

1
나는 당신의 대답을 무시하지 않는다는 것을 분명히하고 싶습니다. 그것은 이다 유용합니다. 은 우리가 한 이후 효율성 주장이다와 함께 문제를 가지고 비트 수행 DB2 / Z의 평가와 사이에 진짜 차이가 없다 발견 count(*)하고 count(1). 그것이 다른 DBMS 의 경우이든 상관 없습니다.
paxdiablo

3
"다른 모든 것들은 오해의 소지가 있으며 DB2에서 MySQL로 이동할 때 (예를 들어) 급격히 변할 수 있습니다." SELECT 1의 구현 차이보다 DBMS를 이동할 때 SELECT COUNT (*)의 성능 저하로 인해 물릴 가능성이 훨씬 높습니다 또는 COUNT (1). 나는 원하는 행동을 기본값으로하기 위해 옵티 마이저 또는 컴파일러에 의존하기보다는 달성하고자하는 것을 정확하게 명확하게 표현하는 코드를 작성하는 확고한 신자입니다.
윈스턴 스미스

1
잘못된 설명 "COUNT (*)"는 '행 수 계산'이 완전히 중지되었음을 의미합니다. 특정 열에 액세스 할 필요가 없습니다. 그리고 대부분의 경우 고유 인덱스만으로도 행 자체에 액세스 할 필요조차 없습니다.
제임스 앤더슨

9

당신이 사용할 수있는:

SELECT 1 FROM MyTable WHERE... LIMIT 1

select 1불필요한 필드 확인을 방지하는 데 사용 합니다.

사용 LIMIT 1 불필요한 행의 검사를 방지 할 수 있습니다.


3
좋은 지적하지만 제한은 MySQL과 PostgreSQL을 작동, SQL Server의 정상 작동, 당신은 당신의 대답에 유의해야한다
레오 Gurdian

0

나는 이런 식으로 사용하고 있습니다 :

IIF(EXISTS (SELECT TOP 1 1 
                FROM Users 
                WHERE FirstName = 'John'), 1, 0) AS DoesJohnExist

0

다른 옵션 :

SELECT CASE
    WHEN EXISTS (
        SELECT 1
        FROM [MyTable] AS [MyRecord])
    THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.