LIKE 연산자의 카디널리티 예상치 (로컬 변수)


24

LIKE알 수없는 시나리오에 대해 모든 최적화 에서 연산자 를 사용할 때 레거시 및 새로운 CE 모두 9 % 추정치를 사용 한다는 인상을 받았습니다 (관련 통계를 사용할 수 있고 쿼리 최적화 프로그램이 선택성 추측에 의존 할 필요가 없다고 가정).

신용 데이터베이스에 대해 아래 쿼리를 실행할 때 다른 CE에 따라 다른 추정치를 얻습니다. 새 CE에서 예상했던 900 행의 추정치를 수신하고 레거시 CE에서 추정치 241.416을 수신하며이 추정치가 어떻게 도출되는지 파악할 수 없습니다. 누구나 빛을 비출 수 있습니까?

-- New CE (Estimate = 900)
DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM [Credit].[dbo].[member]
WHERE [lastname] LIKE @LastName;

-- Forcing Legacy CE (Estimate = 241.416)
DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM [Credit].[dbo].[member]
WHERE [lastname] LIKE @LastName
OPTION (
QUERYTRACEON 9481,
QUERYTRACEON 9292,
QUERYTRACEON 9204,
QUERYTRACEON 3604
);

내 시나리오에서는 이미 신용 데이터베이스가 호환성 수준 120으로 설정되어 있으므로 두 번째 쿼리에서 추적 플래그를 사용하여 레거시 CE를 강제하고 쿼리 옵티마이 저가 사용 / 고려한 통계에 대한 정보를 제공하는 이유는 무엇입니까? 'lastname'에 대한 열 통계가 사용되고 있음을 알 수 있지만 241.416의 추정치가 도출되는 방법을 여전히 해결할 수는 없습니다.

이 Itzik Ben-Gan 기사 이외의 온라인 에서는 "알 수없는 시나리오에 대해 LIKE 조건자를 사용할 때 레거시 및 새 CE 모두 9 % 추정값을 사용합니다."라는 내용의 온라인 내용을 찾을 수 없었습니다 . 해당 게시물의 정보가 잘못된 것 같습니다.

답변:


28

LIKE 귀하의 경우에 대한 추측 은 다음을 기반으로합니다.

  • G: 표준 9 % 추측 ( sqllang!x_Selectivity_Like)
  • M: 6의 계수 (마법 번호)
  • D: 평균 데이터 길이 (바이트) (통계에서), 정수로 내림

특히 다음을 sqllang!CCardUtilSQL7::ProbLikeGuess사용합니다.

Selectivity (S) = G / M * LOG(D)

노트:

  • LOG(D)경우 용어는 생략 D1과 2 사이이다.
  • 경우 D1보다 작은 (없거나 포함한 NULL통계) :
    D = FLOOR(0.5 * maximum column byte length)

이런 종류의 기발함과 복잡성은 원래 CE의 전형적인 특징입니다.

질문 예에서 평균 길이는 5 (내림차순에서 5.6154 DBCC SHOW_STATISTICS)입니다.

추정치 = 10,000 * (0.09 / 6 * LOG (5)) = 241.416

다른 예제 값 :

 D   = S에 대한 공식을 사용하여 추정
 15 = 406.208
 14 = 395.859
 13 = 384.742
 12 = 372.736
 11 = 359.684
 10 = 345.388
 09 = 329.584
 08 = 311.916
 07 = 291.887
 06 = 268.764
 05 = 241.416
 04 = 207.944
 03 = 164.792
 02 = 150.000 (LOG 미사용)
 01 = 150.000 (LOG 미사용)
 00 = 291.887 (LOG 7) / * FLOOR (0.5 * 15) [15는 성이 varchar (15)이므로 * 15

테스트 장비

DECLARE
    @CharLength integer = 5, -- Set length here
    @Counter integer = 1;

CREATE TABLE #T (c1 varchar(15) NULL);

-- Add 10,000 rows
SET NOCOUNT ON;
SET STATISTICS XML OFF;

BEGIN TRANSACTION;
WHILE @Counter <= 10000
BEGIN
    INSERT #T (c1) VALUES (REPLICATE('X', @CharLength));
    SET @Counter = @Counter + 1;
END;
COMMIT TRANSACTION;

SET NOCOUNT OFF;
SET STATISTICS XML ON;

-- Test query
DECLARE @Like varchar(15);
SELECT * FROM #T AS T 
WHERE T.c1 LIKE @Like;

DROP TABLE #T;

15

레거시 CE로 SQL Server 2014에서 테스트했으며 카디널리티 추정치로 9 %를 얻지 못했습니다. 온라인에서 정확한 것을 찾을 수 없어서 몇 가지 테스트를 해본 결과 시도한 모든 테스트 사례에 맞는 모델을 찾았지만 그것이 완료되었는지 확신 할 수 없습니다.

내가 찾은 모델에서 추정치는 테이블의 행 수, 필터링 된 열에 대한 통계의 평균 키 길이 및 때로는 필터링 된 열의 데이터 유형 길이에서 파생됩니다. 추정에 사용되는 두 가지 다른 공식이 있습니다.

FLOOR (평균 키 길이) = 0이면 추정 공식은 열 통계를 무시하고 데이터 유형 길이를 기반으로 추정을 작성합니다. VARCHAR (N)으로 만 테스트 했으므로 NVARCHAR (N)에 대해 다른 수식이있을 수 있습니다. VARCHAR (N)의 공식은 다음과 같습니다.

(행 추정) = (표의 행) * (-0.004869 + 0.032649 * log10 (데이터 유형의 길이))

이것은 매우 잘 맞지만 완벽하게 정확하지는 않습니다.

첫 번째 공식 그래프

x 축은 데이터 유형의 길이이고 y 축은 1 백만 개의 행이있는 테이블의 예상 행 수입니다.

열에 대한 통계가 없거나 열에 평균 키 길이가 1 미만이되도록 충분한 NULL 값이있는 경우 쿼리 최적화 프로그램에서이 수식을 사용합니다.

예를 들어, VARCHAR (50)에서 필터링하고 열 통계가없는 150k 개의 행이있는 테이블이 있다고 가정하십시오. 행 추정 예측은 다음과 같습니다.

150000 * (-0.004869 + 0.032649 * log10 (50)) = 7590.1 행

그것을 테스트하는 SQL :

CREATE TABLE X_CE_LIKE_TEST_1 (
STRING VARCHAR(50)
);

CREATE STATISTICS X_STAT_CE_LIKE_TEST_1 ON X_CE_LIKE_TEST_1 (STRING) WITH NORECOMPUTE;

WITH
    L0 AS (SELECT 1 AS c UNION ALL SELECT 1),
    L1 AS (SELECT 1 AS c FROM L0 A CROSS JOIN L0 B),
    L2 AS (SELECT 1 AS c FROM L1 A CROSS JOIN L1 B),
    L3 AS (SELECT 1 AS c FROM L2 A CROSS JOIN L2 B),
    L4 AS (SELECT 1 AS c FROM L3 A CROSS JOIN L3 B CROSS JOIN L2 C),
    NUMS AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS NUM FROM L4)  
    INSERT INTO X_CE_LIKE_TEST_1 WITH (TABLOCK) (STRING)
    SELECT TOP (150000) 'ZZZZZ'
    FROM NUMS
    ORDER BY NUM;

DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM X_CE_LIKE_TEST_1
WHERE STRING LIKE @LastName;

SQL Server는 7242.47의 예상 행 수를 제공합니다.

FLOOR (평균 키 길이)> = 1 인 경우 FLOOR (평균 키 길이) 값을 기반으로하는 다른 수식이 사용됩니다. 다음은 내가 시도한 일부 값의 표입니다.

1    1.5%
2    1.5%
3    1.64792%
4    2.07944%
5    2.41416%
6    2.68744%
7    2.91887%
8    3.11916%
9    3.29584%
10   3.45388%

FLOOR (평균 키 길이) <6 인 경우 위 표를 사용하십시오. 그렇지 않으면 다음 방정식을 사용하십시오.

(행 추정) = (표의 행) * (-0.003381 + 0.034539 * log10 (FLOOR (평균 키 길이)))

이것은 다른 것보다 더 잘 맞지만 여전히 완벽하게 정확하지는 않습니다.

두 번째 공식 그래프

x 축은 평균 키 길이이고 y 축은 1 백만 행이있는 테이블의 예상 행 수입니다.

다른 예를 제공하기 위해 필터링 된 열의 통계에 대해 평균 키 길이가 5.5 인 행이 10k 인 테이블이 있다고 가정하십시오. 행 추정치는 다음과 같습니다.

10000 * 0.241416 = 241.416 행.

그것을 테스트하는 SQL :

CREATE TABLE X_CE_LIKE_TEST_2 (
STRING VARCHAR(50)
);

WITH
    L0 AS (SELECT 1 AS c UNION ALL SELECT 1),
    L1 AS (SELECT 1 AS c FROM L0 A CROSS JOIN L0 B),
    L2 AS (SELECT 1 AS c FROM L1 A CROSS JOIN L1 B),
    L3 AS (SELECT 1 AS c FROM L2 A CROSS JOIN L2 B),
    L4 AS (SELECT 1 AS c FROM L3 A CROSS JOIN L3 B CROSS JOIN L2 C),
    NUMS AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS NUM FROM L4)  
    INSERT INTO X_CE_LIKE_TEST_2 WITH (TABLOCK) (STRING)
    SELECT TOP (10000) 
    CASE 
      WHEN NUM % 2 = 1 THEN REPLICATE('Z', 5) 
      ELSE REPLICATE('Z', 6)
    END
    FROM NUMS
    ORDER BY NUM;

CREATE STATISTICS X_STAT_CE_LIKE_TEST_2 ON X_CE_LIKE_TEST_2 (STRING) 
WITH NORECOMPUTE, FULLSCAN;

DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM X_CE_LIKE_TEST_2
WHERE STRING LIKE @LastName;

행 추정치는 241.416이며 질문에있는 것과 일치합니다. 테이블에없는 값을 사용하면 약간의 오류가 발생합니다.

이 모델은 완벽하지는 않지만 일반적인 동작을 잘 보여줍니다.

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