在 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)
)
查询A:
SELECT TOP 20
Email,
DateAndTime,
Serial
FROM
EmailIdx WITH (NOLOCK)
WHERE
Email = '[email protected]'
AND DateAndTime < 2412230000000000000
AND DateAndTime > 2402110000000000000
ORDER BY
DateAndTime DESC
查询B:
-- 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
两个查询都返回正确的结果,但第一个查询运行非常低效的查询计划,似乎忽略了 12 月分区中的所有日期将 > 11 月分区等这一点。
使用
WHERE
Email = '[email protected]'
AND DateAndTime < CAST(2412230000000000000 AS BIGINT)
AND DateAndTime > CAST(2402110000000000000 AS BIGINT)
文字
2412230000000000000
等是decimal
而不是bigint
并且数据类型不匹配导致计划效率较低。