В SQL Server запрос B выполняется в сотни раз быстрее, чем запрос A. Всего существует всего 12 разделов. Как сделать запрос B таким же простым, как запрос A, но сохранить производительность?
Соответствующие операторы SQL:
CREATE PARTITION FUNCTION PartitionFunction (bigint)
AS RANGE RIGHT
FOR VALUES (
2401010000000000000,
2402010000000000000,
2403010000000000000,
2404010000000000000,
2405010000000000000,
2406010000000000000,
2407010000000000000,
2408010000000000000,
2409010000000000000,
2410010000000000000,
2411010000000000000,
2412010000000000000
)
CREATE PARTITION SCHEME PartitionScheme
AS PARTITION PartitionFunction
ALL TO ([PRIMARY])
CREATE TABLE [dbo].[EmailIdx]
(
[Email] [varchar](255) NOT NULL,
[DateAndTime] [bigint] NOT NULL,
[Serial] [bigint] NOT NULL,
CONSTRAINT [PK_Email]
PRIMARY KEY CLUSTERED ([Email] ASC, [DateAndTime] ASC, [Serial] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) on PartitionScheme([DateAndTime])
)
Запрос А:
SELECT TOP 20
Email,
DateAndTime,
Serial
FROM
EmailIdx WITH (NOLOCK)
WHERE
Email = '[email protected]'
AND DateAndTime < 2412230000000000000
AND DateAndTime > 2402110000000000000
ORDER BY
DateAndTime DESC
Запрос Б:
-- Union all partitions from February to December starting from December
WITH CombinedResults AS
(
SELECT TOP 20
Email,
DateAndTime,
Serial
FROM
EmailIdx WITH (NOLOCK)
WHERE
$PARTITION.PartitionFunction(DateAndTime) = 12
AND Email = '[email protected]'
AND DateAndTime < 2412230000000000000
AND DateAndTime > 2402110000000000000
ORDER BY
DateAndTime DESC
UNION ALL
SELECT TOP 20
Email,
DateAndTime,
Serial
FROM
EmailIdx WITH (NOLOCK)
WHERE
$PARTITION.PartitionFunction(DateAndTime) = 11
AND Email = '[email protected]'
AND DateAndTime < 2412230000000000000
AND DateAndTime > 2402110000000000000
ORDER BY
DateAndTime DESC
UNION ALL
SELECT TOP 20
Email,
DateAndTime,
Serial
FROM
EmailIdx WITH (NOLOCK)
WHERE
$PARTITION.PartitionFunction(DateAndTime) = 10
AND Email = '[email protected]'
AND DateAndTime < 2412230000000000000
AND DateAndTime > 2402110000000000000
ORDER BY
DateAndTime DESC
UNION ALL
SELECT TOP 20
Email,
DateAndTime,
Serial
FROM
EmailIdx WITH (NOLOCK)
WHERE
$PARTITION.PartitionFunction(DateAndTime) = 9
AND Email = '[email protected]'
AND DateAndTime < 2412230000000000000
AND DateAndTime > 2402110000000000000
ORDER BY
DateAndTime DESC
UNION ALL
SELECT TOP 20
Email,
DateAndTime,
Serial
FROM
EmailIdx WITH (NOLOCK)
WHERE
$PARTITION.PartitionFunction(DateAndTime) = 8
AND Email = '[email protected]'
AND DateAndTime < 2412230000000000000
AND DateAndTime > 2402110000000000000
ORDER BY
DateAndTime DESC
UNION ALL
SELECT TOP 20
Email,
DateAndTime,
Serial
FROM
EmailIdx WITH (NOLOCK)
WHERE
$PARTITION.PartitionFunction(DateAndTime) = 7
AND Email = '[email protected]'
AND DateAndTime < 2412230000000000000
AND DateAndTime > 2402110000000000000
ORDER BY
DateAndTime DESC
UNION ALL
SELECT TOP 20
Email,
DateAndTime,
Serial
FROM
EmailIdx WITH (NOLOCK)
WHERE
$PARTITION.PartitionFunction(DateAndTime) = 6
AND Email = '[email protected]'
AND DateAndTime < 2412230000000000000
AND DateAndTime > 2402110000000000000
ORDER BY
DateAndTime DESC
UNION ALL
SELECT TOP 20
Email,
DateAndTime,
Serial
FROM
EmailIdx WITH (NOLOCK)
WHERE
$PARTITION.PartitionFunction(DateAndTime) = 5
AND Email = '[email protected]'
AND DateAndTime < 2412230000000000000
AND DateAndTime > 2402110000000000000
ORDER BY
DateAndTime DESC
UNION ALL
SELECT TOP 20
Email,
DateAndTime,
Serial
FROM
EmailIdx WITH (NOLOCK)
WHERE
$PARTITION.PartitionFunction(DateAndTime) = 4
AND Email = '[email protected]'
AND DateAndTime < 2412230000000000000
AND DateAndTime > 2402110000000000000
ORDER BY
DateAndTime DESC
UNION ALL
SELECT TOP 20
Email,
DateAndTime,
Serial
FROM
EmailIdx WITH (NOLOCK)
WHERE
$PARTITION.PartitionFunction(DateAndTime) = 3
AND Email = '[email protected]'
AND DateAndTime < 2412230000000000000
AND DateAndTime > 2402110000000000000
ORDER BY
DateAndTime DESC
UNION ALL
SELECT TOP 20
Email,
DateAndTime,
Serial
FROM
EmailIdx WITH (NOLOCK)
WHERE
$PARTITION.PartitionFunction(DateAndTime) = 2
AND Email = '[email protected]'
AND DateAndTime < 2412230000000000000
AND DateAndTime > 2402110000000000000
ORDER BY
DateAndTime DESC
)
SELECT TOP 20
Email,
DateAndTime,
Serial
FROM
CombinedResults
Оба запроса возвращают правильные результаты, но первый выполняет очень неэффективный план запроса, в котором, похоже, не учитывается тот момент, что все даты в декабрьских разделах будут > ноябрьских разделов и т. д. и т. п.
Я понятия не имею, почему вы просто не используете datetime2
здесь и не используете свою собственную схему кодирования даты и времени как целые числа, но в любом случае вам следует использовать
WHERE
Email = '[email protected]'
AND DateAndTime < CAST(2412230000000000000 AS BIGINT)
AND DateAndTime > CAST(2402110000000000000 AS BIGINT)
Литералы 2412230000000000000
и т. д. decimal(19,0)
не bigint
определены в функции разделения, а несоответствие типов данных приводит к добавлению дополнительных операторов и увеличению вероятности менее эффективного плана.
При этом я получаю план, который посещает только 11 ожидаемых разделов, пронумерованных от 3
до 13
(как того требует BETWEEN $PARTITION.PartitionFunction(2402110000000000000) AND $PARTITION.PartitionFunction(2412230000000000000)
), и без оператора сортировки.
(В отличие от этого плана с несовпадающими типами данных)
Спасибо большое, это полностью решило проблему. Есть причина не использовать DateTime, которую я указал по причинам IP.
«Все типы данных допустимы для использования в качестве столбцов секционирования, за исключением text, ntext, image, xml, timestamp, varchar(max), nvarchar(max), varbinary(max), псевдонимов типов данных или пользовательских типов данных CLR. " Learn.microsoft.com/en-us/sql/t-sql/statements/…