Почему зарплата> 0 не вызывает сканирование таблицы / индекса - PullRequest
0 голосов
/ 04 мая 2018

У меня есть тестовая таблица для этого упражнения:

CREATE DATABASE QueryTest
GO
USE QueryTest

CREATE TABLE Person
(
    ID INT IDENTITY (1,1),
    FirstName   NVARCHAR(50),
    SurName     NVARCHAR(50),
    Salary      MONEY
)

INSERT INTO Person
SELECT  TOP 2000
        FirstName,
        LastName,
        RAND(CAST( NEWID() AS varbinary)) *100000
FROM    [AdventureWorks2014].[Person].[Person]
ORDER   BY NEWID()

CREATE INDEX IX_Person_Salary ON Person
(
    Salary
)

Если я выполню следующее, я получу сканирование таблицы, чего я и ожидал

SELECT Salary FROM Person

Если я сделаю это, я получу индексный поиск - опять-таки, вполне ожидаемый,

SELECT Salary FROM Person WHERE Salary > 270

Однако, если я сделаю это:

SELECT Salary FROM Person WHERE Salary > 0

Я получаю поиск по индексу (несмотря на то, что он возвращает все строки из таблицы

Кроме того, если я бегу

SELECT Salary FROM Person
SELECT Salary FROM Person WHERE Salary > 0

в одной партии, они оба составляют 50% от партии

Что здесь происходит? Почему SQL Server использует поиск, когда предложение WHERE присутствует, если все строки будут возвращены?

Почему индекс ищет такую ​​же стоимость, как индексное сканирование?

У меня сложилось впечатление, что SQL Server будет использовать свою статистику, чтобы оценить, сколько строк должно быть возвращено, и затем соответствующим образом спланировать его выполнение. Статистика скажет, что> 0 - это все строки, и, следовательно, сканирование в этом случае будет менее затратным?

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Здесь происходит пара вещей:

Во-первых: не нужно сканировать таблицы, потому что ваши Данные находятся в индексе некластерности (представьте себе, что это копия с меньшим порядком - копия таблицы, которая содержит только зарплату). Получать все данные из индекса быстрее.

Во-вторых:> 0 вещь и производительность разделены.

Ваше определение столбца для [Зарплата] допускает значения NULL. Когда SQL создает план выполнения, он предполагает, что в таблице могут быть значения NULL, поэтому не может явно предсказать, что> 0 вернет все значения. SQL «планирует» поиск, но в итоге «на самом деле» выполняет сканирование. План фактического выполнения - это предполагаемый план выполнения, но с дополнительными показателями.

Демонстрация кода ниже демонстрирует это поведение с 52% 48% -ным разделением в моей среде.

CREATE TABLE #TMP1
(
    ID INT IDENTITY (1,1),
    FirstName   NVARCHAR(50),
    SurName     NVARCHAR(50),
    Salary      MONEY
)

CREATE TABLE #TMP2
(
    ID INT IDENTITY (1,1),
    FirstName   NVARCHAR(50),
    SurName     NVARCHAR(50),
    Salary      MONEY NOT NULL
)
GO

INSERT INTO #TMP1
SELECT  'xxxxx','xxxxx',RAND(CAST( NEWID() AS varbinary)) *100000
GO 2000


INSERT INTO #TMP2
SELECT FirstName,SurName,Salary FROM #TMP1


CREATE INDEX IX_Person_Salary ON #TMP1
(
    Salary
)
CREATE INDEX IX_Person_Salary ON #TMP2
(
    Salary
)


SELECT Salary FROM #TMP1 WHERE Salary > 0
SELECT Salary FROM #TMP2 WHERE Salary > 0

Обновление

Проверьте гистограмму для своего индекса, если он начинается с 0, тогда вам нужно сделать> = 0, чтобы получить полное сканирование.

0 голосов
/ 04 мая 2018

Запрос извлекает только один столбец Person:

SELECT Salary FROM Person WHERE Salary > 0 

В то же время существует только одно условие Salary > 0, использующее тот же столбец Person.

Если в столбце зарплаты есть индекс, то дешевле сканировать только этот индекс по всей таблице. Это так называемое покрытие индекса для этого запроса, поскольку индекс содержит всю информацию, необходимую для выполнения этого запроса, база данных считывает всю необходимую информацию из файла индекса, не доходя до таблицы.

...