복붙노트

[SQL] 사용하여 하위 쿼리 * 1를 존재하거나 존재

SQL

사용하여 하위 쿼리 * 1를 존재하거나 존재

나는이 같은 검사를 EXISTS 작성하는 데 사용 :

IF EXISTS (SELECT * FROM TABLE WHERE Columns=@Filters)
BEGIN
   UPDATE TABLE SET ColumnsX=ValuesX WHERE Where Columns=@Filters
END

이전의 삶에서 DBA 년대 중 하나는 내가이 EXISTS 절 수행 할 때, 사용하는 대신 SELECT의 1을 선택하는 것이 나에게 말했다 *

IF EXISTS (SELECT 1 FROM TABLE WHERE Columns=@Filters)
BEGIN
   UPDATE TABLE SET ColumnsX=ValuesX WHERE Columns=@Filters
END

이 정말 달라 지나요?

해결법

  1. ==============================

    1.아니, SQL 서버는 스마트이며 존재를 위해 사용되는 알고 있으며, 시스템에 데이터를 반환합니다.

    아니, SQL 서버는 스마트이며 존재를 위해 사용되는 알고 있으며, 시스템에 데이터를 반환합니다.

    Quoth 마이크로 소프트 : http://technet.microsoft.com/en-us/library/ms189259.aspx?ppud=4

    자신을 확인하려면 다음을 실행하십시오 :

    SELECT whatever
      FROM yourtable
     WHERE EXISTS( SELECT 1/0
                     FROM someothertable 
                    WHERE a_valid_clause )
    

    실제로 SELECT 목록에 뭔가를하고있는 경우, 그것은 제로 오류로 사업부를 던질 것입니다. 그것은하지 않습니다.

    편집 : 참고는 SQL 표준이 실제로 이것에 대해 이야기합니다.

    ANSI SQL 1992 표준 페이지 191 http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt

  2. ==============================

    2.이 오해하는 이유는 아마도 그것 때문에 모든 열을 읽는 끝날 것이라는 믿음이다. 그렇지 않은 것을 쉽게 알 수있다.

    이 오해하는 이유는 아마도 그것 때문에 모든 열을 읽는 끝날 것이라는 믿음이다. 그렇지 않은 것을 쉽게 알 수있다.

    CREATE TABLE T
    (
    X INT PRIMARY KEY,
    Y INT,
    Z CHAR(8000)
    )
    
    CREATE NONCLUSTERED INDEX NarrowIndex ON T(Y)
    
    IF EXISTS (SELECT * FROM T)
        PRINT 'Y'
    

    계획을 제공합니다

    SQL Server가 인덱스가 모든 열을 포함하지 않는다는 사실에도 불구하고 결과를 확인하기 위해 사용할 수있는 좁은 인덱스를 사용할 수 있었다이 보여줍니다. 인덱스 액세스 세미 조인 연산자하에있는이 즉시 첫 번째 행으로 리턴 스캔 막을 수 있다는 것을 의미한다.

    그것은 분명하다 그래서 위의 믿음은 잘못된 것입니다.

    그러나 쿼리 최적화 팀의 코너 커닝햄은 그가 일반적으로는 쿼리의 편집에있는 작은 성능 차이를 만들 수 있습니다이 경우에 하나를 선택 사용하는 여기에 설명합니다.

    나는 컬럼의 다양한 숫자 빈 테이블이 쿼리를 표현하는 네 가지 방법을 시험했다. SELECT Other_Not_Null_Column 대 SELECT primary_key와 대 SELECT * 대 1을 선택합니다.

    I는 OPTION (RECOMPILE) 초당 실행의 평균 측정을 이용하여 루프에 쿼리를 실행. 아래의 결과

    +-------------+----------+---------+---------+--------------+
    | Num of Cols |    *     |    1    |   PK    | Not Null col |
    +-------------+----------+---------+---------+--------------+
    | 2           | 2043.5   | 2043.25 | 2073.5  | 2067.5       |
    | 4           | 2038.75  | 2041.25 | 2067.5  | 2067.5       |
    | 8           | 2015.75  | 2017    | 2059.75 | 2059         |
    | 16          | 2005.75  | 2005.25 | 2025.25 | 2035.75      |
    | 32          | 1963.25  | 1967.25 | 2001.25 | 1992.75      |
    | 64          | 1903     | 1904    | 1936.25 | 1939.75      |
    | 128         | 1778.75  | 1779.75 | 1799    | 1806.75      |
    | 256         | 1530.75  | 1526.5  | 1542.75 | 1541.25      |
    | 512         | 1195     | 1189.75 | 1203.75 | 1198.5       |
    | 1024        | 694.75   | 697     | 699     | 699.25       |
    +-------------+----------+---------+---------+--------------+
    | Total       | 17169.25 | 17171   | 17408   | 17408        |
    +-------------+----------+---------+---------+--------------+
    

    알 수있는 바와 같이 SELECT 1 SELECT 사이에 일관된 우승자 *와 두 접근 (가) 무시할 수의 차이가 없다. 선택하지 널 COL 및 SELECT PK는 약간 빠른하지만 표시 않습니다.

    쿼리의 네 개의 테이블 증가의 열 수와 같은 성능 저하.

    테이블이 관계를 비어 같이 열 메타 데이터의 양에 의해서만 천명 보인다. COUNT (1)의 경우 아래에서 그 과정에서 어떤 시점에서 COUNT (*)에 다시됩니다 것을 쉽게 알 수있다.

    SET SHOWPLAN_TEXT ON;
    
    GO
    
    SELECT COUNT(1)
    FROM master..spt_values
    

    어느 다음과 같은 계획을 제공합니다

      |--Compute Scalar(DEFINE:([Expr1003]=CONVERT_IMPLICIT(int,[Expr1004],0)))
           |--Stream Aggregate(DEFINE:([Expr1004]=Count(*)))
                |--Index Scan(OBJECT:([master].[dbo].[spt_values].[ix2_spt_values_nu_nc]))
    

    SQL Server 프로세스에 디버거를 연결하고 무작위로 아래를 실행하는 동안 파괴

    DECLARE @V int 
    
    WHILE (1=1)
        SELECT @V=1 WHERE EXISTS (SELECT 1 FROM ##T) OPTION(RECOMPILE)
    

    나는 테이블이 참 케이스를 들어 SELECT (1)가 사용되는 경우에도 시간 로딩 열 메타 데이터의 큰 비율을 (지출을 나타내는 아래 대부분의 시간의 같은과 같은 호출 스택의 모습을 1,024 열이있는 경우에 그 발견 테이블 1 열이있는 곳에 무작위로 파괴는) 10 개 시도에서 호출 스택의이 비트를 명중하지 않았다

    sqlservr.exe!CMEDAccess::GetProxyBaseIntnl()  - 0x1e2c79 bytes  
    sqlservr.exe!CMEDProxyRelation::GetColumn()  + 0x57 bytes   
    sqlservr.exe!CAlgTableMetadata::LoadColumns()  + 0x256 bytes    
    sqlservr.exe!CAlgTableMetadata::Bind()  + 0x15c bytes   
    sqlservr.exe!CRelOp_Get::BindTree()  + 0x98 bytes   
    sqlservr.exe!COptExpr::BindTree()  + 0x58 bytes 
    sqlservr.exe!CRelOp_FromList::BindTree()  + 0x5c bytes  
    sqlservr.exe!COptExpr::BindTree()  + 0x58 bytes 
    sqlservr.exe!CRelOp_QuerySpec::BindTree()  + 0xbe bytes 
    sqlservr.exe!COptExpr::BindTree()  + 0x58 bytes 
    sqlservr.exe!CScaOp_Exists::BindScalarTree()  + 0x72 bytes  
    ... Lines omitted ...
    msvcr80.dll!_threadstartex(void * ptd=0x0031d888)  Line 326 + 0x5 bytes C
    kernel32.dll!_BaseThreadStart@8()  + 0x37 bytes 
    

    이 매뉴얼 프로파일 시도는 두 경우에 대한 컴파일 시간을 소모 기능의 매우 다른 선택을 보여줍니다 VS 2012 코드 프로파일 러 (상위 15 기능 15 가지 기능 1 열 대 1,024 열)에 의해 백업됩니다.

    모두 SELECT 1 *이 버전 확인 열 권한을 바람과 사용자가 테이블의 모든 컬럼에 대한 액세스 권한이 부여되지 않은 경우 실패를 선택합니다.

    예제 나는 힙에 대화에서 cribbed

    CREATE USER blat WITHOUT LOGIN;
    GO
    CREATE TABLE dbo.T
    (
    X INT PRIMARY KEY,
    Y INT,
    Z CHAR(8000)
    )
    GO
    
    GRANT SELECT ON dbo.T TO blat;
    DENY SELECT ON dbo.T(Z) TO blat;
    GO
    EXECUTE AS USER = 'blat';
    GO
    
    SELECT 1
    WHERE  EXISTS (SELECT 1
                   FROM   T); 
    /*  ↑↑↑↑ 
    Fails unexpectedly with 
    
    The SELECT permission was denied on the column 'Z' of the 
               object 'T', database 'tempdb', schema 'dbo'.*/
    
    GO
    REVERT;
    DROP USER blat
    DROP TABLE T
    

    하나는 작은 명백한 차이 SELECT some_not_null_col를 사용하여 단지 특정 컬럼에 대한 권한을 확인하는 바람이 있다는 것을 추측 할 수 있도록 (하지만 여전히 모든 메타 데이터를로드합니다). 아무것도 기본 테이블 증가의 열 수가 작아지는 경우 둘 사이의 비율 차이가 접근 그러나이 사실로 적합하지 않는 것 같습니다.

    어쨌든 나는 밖으로 돌진되지 않고 차이가 매우 작은 쿼리 컴파일시에만 명백한 바와 같이이 양식에 내 모든 쿼리를 변경. 그 이후의 실행은 캐시 된 계획은 다음을 준 사용할 수 있도록 OPTION (RECOMPILE)을 제거.

    +-------------+-----------+------------+-----------+--------------+
    | Num of Cols |     *     |     1      |    PK     | Not Null col |
    +-------------+-----------+------------+-----------+--------------+
    | 2           | 144933.25 | 145292     | 146029.25 | 143973.5     |
    | 4           | 146084    | 146633.5   | 146018.75 | 146581.25    |
    | 8           | 143145.25 | 144393.25  | 145723.5  | 144790.25    |
    | 16          | 145191.75 | 145174     | 144755.5  | 146666.75    |
    | 32          | 144624    | 145483.75  | 143531    | 145366.25    |
    | 64          | 145459.25 | 146175.75  | 147174.25 | 146622.5     |
    | 128         | 145625.75 | 143823.25  | 144132    | 144739.25    |
    | 256         | 145380.75 | 147224     | 146203.25 | 147078.75    |
    | 512         | 146045    | 145609.25  | 145149.25 | 144335.5     |
    | 1024        | 148280    | 148076     | 145593.25 | 146534.75    |
    +-------------+-----------+------------+-----------+--------------+
    | Total       | 1454769   | 1457884.75 | 1454310   | 1456688.75   |
    +-------------+-----------+------------+-----------+--------------+
    

    사용 된 테스트 스크립트 나는 여기에서 찾을 수 있습니다

  3. ==============================

    3.알고 가장 좋은 방법은 성능 테스트 두 버전이며, 두 버전에 대한 실행 계획을 확인하십시오. 열이 많은 테이블을 선택합니다.

    알고 가장 좋은 방법은 성능 테스트 두 버전이며, 두 버전에 대한 실행 계획을 확인하십시오. 열이 많은 테이블을 선택합니다.

  4. ==============================

    4.이 SQL Server의 차이는 없습니다 그것은 SQL Server에서 문제되지 않았어요. 최적화는이 같은 것을 알고있다. 당신이 실행 계획을 보면, 당신은 그들이 동일한 것을 볼 수 있습니다.

    이 SQL Server의 차이는 없습니다 그것은 SQL Server에서 문제되지 않았어요. 최적화는이 같은 것을 알고있다. 당신이 실행 계획을 보면, 당신은 그들이 동일한 것을 볼 수 있습니다.

  5. ==============================

    5.개인적으로 나는 그들이 동일한 쿼리 계획을 최적화하지 믿고 아주, 아주 하드를 찾을 수 있습니다. 그러나 특정 상황에서 알 수있는 유일한 방법은 그것을 테스트하는 것입니다. 당신이 할 경우 다시 신청 해주세요!

    개인적으로 나는 그들이 동일한 쿼리 계획을 최적화하지 믿고 아주, 아주 하드를 찾을 수 있습니다. 그러나 특정 상황에서 알 수있는 유일한 방법은 그것을 테스트하는 것입니다. 당신이 할 경우 다시 신청 해주세요!

  6. ==============================

    6.아니 실제 차이가 있지만 아주 작은 성능 저하가있을 수 있습니다. 당신이 필요로하는 것보다 엄지 손가락의 규칙으로 당신은 더 많은 데이터를 요구해서는 안된다.

    아니 실제 차이가 있지만 아주 작은 성능 저하가있을 수 있습니다. 당신이 필요로하는 것보다 엄지 손가락의 규칙으로 당신은 더 많은 데이터를 요구해서는 안된다.

  7. from https://stackoverflow.com/questions/1597442/subquery-using-exists-1-or-exists by cc-by-sa and MIT license