简体   繁体   中英

Why Optimizer Does Not Use Index Seek on Join

I wonder why the following SELECT statement (below) does not use Index Seek, but Index Scan. Is it just because the number of rows is too small or am I missing something?

Test data:

-- Init Tables

IF OBJECT_ID ( 'tempdb..#wat' ) IS NOT NULL
DROP TABLE #wat;

IF OBJECT_ID ( 'tempdb..#jam' ) IS NOT NULL
DROP TABLE #jam;

CREATE TABLE #wat (
ID INT IDENTITY(1,1) NOT NULL,
Name VARCHAR(15) NOT NULL,
Den DATETIME NOT NULL
)

CREATE TABLE #jam (
ID INT IDENTITY(1,1) NOT NULL,
Name VARCHAR(15) NOT NULL
)

-- Populate Temp Tables with Random Data

DECLARE @length INT
       ,@charpool VARCHAR(255)
       ,@poolLength INT
       ,@RandomString VARCHAR(255)
       ,@LoopCount INT

SET @Length = RAND() * 5 + 8
SET @CharPool = 'abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ23456789'
SET @PoolLength = LEN(@CharPool)
SET @LoopCount = 0
SET @RandomString = ''

WHILE (@LoopCount < 500) 
BEGIN

    INSERT INTO #jam (Name)
    SELECT    SUBSTRING(@Charpool, CONVERT(int, RAND() * @PoolLength), 5)
    SET @LoopCount = @LoopCount + 1

END

-- Insert Rows into Second Temp Table
INSERT INTO #wat( Name, Den )
SELECT TOP 50 Name, GETDATE()
FROM #jam

-- Create Indexes

--DROP INDEX IX_jedna ON #jam
--DROP INDEX IX_dva ON #wat
CREATE INDEX IX_jedna ON #jam (Name) INCLUDE (ID);
CREATE INDEX IX_dva ON #wat (Name) INCLUDE (ID, Den);

-- Select

SELECT *
FROM #jam j
JOIN #wat w
ON w.Name = j.Name

Execution Plan:

在此处输入图片说明

There are several ways for optimiser to do jons: nested loops, hash match or merge join (your case) and may be another. In dependence of your data: count of rows, existed indexes and statistics id decides which one is better.

in your example optimiser assumes that there is many-to-many relation. And you have both tables soret(indexed) by this fields.

why merge join? - it is logically - to move through both tables parallel. And server will have to do that only once.

To make seek as you want, the server have to move thorugh first table once, and have to make seeks in second table a lot of times, since all records have matches in another table. Server will read all records if he seeks. And there no profit when using seek (1000 seeks even more difucult than one simple loop through 1000 records).

if you want seek add some records with no matches and where clause in your query.

UPD

even adding simple

where j.ID = 1

gives you seek

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM