2

나는 우편 번호, 도시, 길이, 위도, 성을 가진 데이터베이스 테이블을 가지고 있습니다.LIKE 쿼리에 대해 1 백만 행의 클러스터형 또는 비 클러스터형 인덱스를 만드시겠습니까?

자동 완성 위젯에 제안 된 코드 (도시 및 지방)를 반환하는 데이 테이블을 한 번 사용합니다.

citypostalcode은 고유 한 레코드를 구성합니다. 쿼리를 3 자로 시작합니다.

이 쿼리는 느리므로 자동 완성 경험이 좋지 않습니다. 어떤 종류의 인덱스가 가장 잘 작동하는지에 대한 정보가 있으면 궁금합니다. Azure SQL 데이터 저장소를 사용하고 있는데 Query Analyzer/Tuning Advisor를 실행할 수 없습니다.

postalCode의 클러스터되지 않은 인덱스와 postalCodecity의 2 열 클러스터 된 인덱스를 시도했습니다. 두 쿼리 모두 동일한 결과를 쿼리에 나타 냈습니다.

Select * 
From PostalCode 
Where code LIKE '%L6J 0%' 

이 테이블을 업데이트하거나 삽입하지 않습니다.

+2

접두어 와일드 카드를 삭제할 수있는 것처럼 보이는 영국 우편 번호입니다. 큰 속도 차이를 만드는 일부 데이터베이스 엔진에서는 원하는 기능을 수행 할 수 있습니까? 처음 몇 글자를 "어디서나 우편 번호"에 매칭하는 데 가치가 있는지 알지 못합니다. 왜냐하면 사람들은 항상 첫 글자부터 입력하기 때문입니다. – halfer

+3

'LIKE' 비교에서 ** leading **'%'를 사용하면 어떤 색인도 당신을 도울 수 없습니다. ** ** 항상 전체 테이블 스캔 결과 ** –

+0

정말 좋은 지적입니다. 저는 실제로 EF/linq을 사용하고 있습니다. 그래서 startswith입니다. 어느 쪽이 거기에 두지 않을 가능성이 있습니다. 왜 SQL Server 관리자에서 테스트했는지 모르겠지만 100 % 정확합니다. 코드와 도시의 Clustered Index가 더 빠르며 선두가 없음 % –

답변

1

우편 번호의 길이가 상당히 짧고 알려져 있기 때문에 (8) 청킹에 적합한 후보입니다. 우편 번호를 모든 구성 청크로 분할하고 시작 위치와 길이로 저장하여 색인 탐색을 활성화합니다.

그래서 예를 들면, 'OX1의 1JZ'등의 우편 번호에 대한 저장, 다음의 모든 문자열 : 여기

start len postcodePart 
1 2 OX 
1 3 OX1 
1 4 OX11 
1 5 OX11J 
1 6 OX11JZ 
2 2 X1 
2 3 X11 
2 4 X11J 
2 5 X11JZ 
3 2 11 
3 3 11J 
3 4 11JZ 
4 2 1J 
4 3 1JZ 
5 2 JZ 

은 샘플 스크립트가 100 개 샘플 우편 번호를 사용하여, 기술을 시연하고 우편 번호를 파쇄하는 방법이다 그리고 방아쇠.

NB !! 이것은 준비가 완료된 코드가 아니며 기술을 보여줄 샘플입니다.

USE tempdb 
GO 

-- https://www.postcodelist.co.uk/ 
--uk-postcodes.csv 

IF OBJECT_ID('dbo.postCodeParts') IS NOT NULL DROP TABLE dbo.postCodeParts 
IF OBJECT_ID('dbo.postCodes') IS NOT NULL DROP TABLE dbo.postCodes 
GO 

CREATE TABLE dbo.postCodes (
    postcodeId    INT IDENTITY CONSTRAINT PK_postCodes PRIMARY KEY, 
    postcode    VARCHAR(8) NOT NULL 

    --... the rest of your columns 

    ) 
GO 


CREATE TABLE dbo.postCodeParts (
    postcodePartId   INT IDENTITY CONSTRAINT PK_postCodeParts PRIMARY KEY NONCLUSTERED, 
    postcodeId    INT NOT NULL FOREIGN KEY REFERENCES dbo.postCodes (postcodeId), 

    totalLen    TINYINT NOT NULL, 
    xStart     TINYINT NOT NULL, 
    xLen     TINYINT NOT NULL, 
    postcodePart   VARCHAR(8) NOT NULL INDEX cdx_postCodeParts CLUSTERED 

    ) 
GO 


-- Add a trimmed copy of the postcode to the parts table, chunked up. 
CREATE TRIGGER dbo.trg_postCodes 
ON dbo.postcodes 
FOR INSERT 
AS 
BEGIN 

    ;WITH cte AS 
    (
    SELECT * 
    FROM (
     VALUES (1), (2), (3), (4), (5), (6), (7), (8) 
     ) x(y) 
    ) 
    INSERT INTO dbo.postCodeParts (postcodeId, totalLen, xStart, xLen, postcodePart) 
    SELECT 
     p.postcodeId, 
     p.xTotalLen, 
     c1.y AS xstart, 
     c2.y AS xlen, 
     SUBSTRING(p.postCode, c1.y, c2.y) AS xstring 
    FROM ( 
     SELECT 
      postcodeId, 
      REPLACE(postcode, ' ', '') postCode, 
      LEN(REPLACE(postcode, ' ', '')) AS xTotalLen 
     FROM inserted 
    ) p 
     CROSS JOIN cte c1 
      CROSS JOIN cte c2 
    WHERE c2.y Between 2 And p.xTotalLen 
     AND ((c2.y) + (c1.y - 1)) <= p.xTotalLen 

END 
GO 


INSERT INTO dbo.postcodes (postcode) 
VALUES 
    ('OX1 1AA'),('OX1 1AB'),('OX1 1AD'),('OX1 1AE'),('OX1 1AF'),('OX1 1AG'),('OX1 1AN'),('OX1 1AS'),('OX1 1AW'),('OX1 1AY'), 
    ('OX1 1AZ'),('OX1 1BD'),('OX1 1BE'),('OX1 1BN'),('OX1 1BP'),('OX1 1BS'),('OX1 1BT'),('OX1 1BU'),('OX1 1BX'),('OX1 1BY'), 
    ('OX1 1BZ'),('OX1 1DA'),('OX1 1DB'),('OX1 1DE'),('OX1 1DF'),('OX1 1DG'),('OX1 1DJ'),('OX1 1DL'),('OX1 1DP'),('OX1 1DQ'), 
    ('OX1 1DS'),('OX1 1DW'),('OX1 1DZ'),('OX1 1EA'),('OX1 1EF'),('OX1 1EJ'),('OX1 1EN'),('OX1 1EP'),('OX1 1EQ'),('OX1 1ER'), 
    ('OX1 1ES'),('OX1 1ET'),('OX1 1EU'),('OX1 1EW'),('OX1 1EX'),('OX1 1GA'),('OX1 1GB'),('OX1 1GD'),('OX1 1GE'),('OX1 1GF'), 
    ('OX1 1GH'),('OX1 1GJ'),('OX1 1GL'),('OX1 1HB'),('OX1 1HD'),('OX1 1HF'),('OX1 1HG'),('OX1 1HH'),('OX1 1HN'),('OX1 1HP'), 
    ('OX1 1HQ'),('OX1 1HR'),('OX1 1HS'),('OX1 1HT'),('OX1 1HU'),('OX1 1HW'),('OX1 1HX'),('OX1 1HY'),('OX1 1HZ'),('OX1 1JA'), 
    ('OX1 1JB'),('OX1 1JD'),('OX1 1JE'),('OX1 1JF'),('OX1 1JG'),('OX1 1JH'),('OX1 1JJ'),('OX1 1JL'),('OX1 1JP'),('OX1 1JQ'), 
    ('OX1 1JR'),('OX1 1JS'),('OX1 1JT'),('OX1 1JU'),('OX1 1JW'),('OX1 1JX'),('OX1 1JY'),('OX1 1JZ'),('OX1 1LB'),('OX1 1LD'), 
    ('OX1 1LE'),('OX1 1LF'),('OX1 1LG'),('OX1 1LJ'),('OX1 1LL'),('OX1 1LQ'),('OX1 1LT'),('OX1 1LU'),('OX1 1LY'),('OX1 1ND') 
GO 

SELECT * FROM dbo.postCodes 
SELECT * FROM dbo.postCodeParts ORDER BY xStart, xLen 

SELECT * 
FROM dbo.postCodes pc 
    INNER JOIN dbo.postCodeParts pcp ON pc.postcodeId = pcp.postcodeId 
WHERE postcodePart = '1J' 
ORDER BY xStart, xLen 
GO 

IF OBJECT_ID('dbo.usp_searchPostCodes') IS NOT NULL DROP PROC dbo.usp_searchPostCodes 
GO 
CREATE PROC dbo.usp_searchPostCodes 

    @searchString VARCHAR(8) 

AS 

    SET NOCOUNT ON 

    --!!TODO add error handling 
    --!!TODO does not deal with middle wildcards or _ wildcard 

    DECLARE @leadingWildCard BIT 
    DECLARE @cleanSearchString VARCHAR(8) 

    SELECT @leadingWildCard = CASE WHEN LEFT(@searchString, 1) = '%' THEN 1 ELSE 0 END 
    SELECT @cleanSearchString = REPLACE(REPLACE(@searchString, ' ', ''), '%', '') 

    -- Debugging 
    --PRINT @leadingWildCard 
    --PRINT @cleanSearchString 

    IF @leadingWildCard = 0 

     -- No leading wildcard, start at position 1 
     SELECT pc.postcode 
     FROM dbo.postCodes pc 
      INNER JOIN dbo.postCodeParts pcp ON pc.postcodeId = pcp.postcodeId 
     WHERE pcp.postcodePart = @cleanSearchString 
      AND pcp.xstart = 1 
     ORDER BY xStart, xLen 

    ELSE 

     -- Leading wildcard, return all positions 
     SELECT pc.postcode 
     FROM dbo.postCodes pc 
      INNER JOIN dbo.postCodeParts pcp ON pc.postcodeId = pcp.postcodeId 
     WHERE pcp.postcodePart = @cleanSearchString 
     ORDER BY xStart, xLen 

RETURN 
GO 


EXEC dbo.usp_searchPostCodes 'OX1 1J%' 
EXEC dbo.usp_searchPostCodes '%X1 1J%' 
GO 


SELECT xStart, xLen, postcodePart 
FROM dbo.postCodes pc 
    INNER JOIN dbo.postCodeParts pcp ON pc.postcodeId = pcp.postcodeId 
WHERE pc.postcode= 'OX1 1JZ' 
ORDER BY xStart, xLen 
+0

이것에 대한 어떤 견해? – wBob

+0

안녕하세요 밥, 오늘 재검 표해 죄송합니다. 그래, 나는 여전히 내가 원하는 성능을 얻지 못하고있다. 그래서 나는 pcode를 깨뜨릴 생각을하기 시작했다. 이것은 제가 생각했던 것 이상의 방법입니다. 이것은 정말로 흥미있는 것처럼 보인다. 그래서 방아쇠 postCodeParts 테이블 채우기위한 것입니다? 이미 우편 번호 표가 있습니다. 또한 이것을 구현 .. 어떻게 실제로 쿼리합니까? 고마워요 밥! –

+0

내 코드 예제를 통해 쿼리하는 방법을 보여줍니다. – wBob