郵便番号の長さがかなり短く、既知であるため(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
接頭辞ワイルドカードを削除できるようなイギリスの郵便番号です。大きなスピードの違いを生むデータベースエンジンでは、必要な機能に対してこれを行うことができますか?最初の数文字を「郵便番号のどこにでも」一致させることに価値があるかどうかはわかりません。人々は常に最初の文字からそれらを入力するからです。 – halfer
'LIKE'比較で** leading **'% 'を使用すると、インデックスはあなたを助けることができません。これは**常に**完全なテーブルスキャンの結果になります –
本当に良い点..私は実際にEF/linqを使用しているので、それはstartswithです。それはおそらくそこに置かないでしょう。なぜ私はSQL Serverマネージャーでそれをテストしていたのかわかりませんが、100%正確です。コードと都市でClustered Indexを使用すると高速化され、先行する%なし –