我知道谷歌搜索这个问题会带来许多解决方案,但它们都不适用于我的情况。
我有一张表:
CREATE TABLE [Batch](
[batch_id] [int] NOT NULL,
...(more columns)
[date] [datetime] NULL)
CONSTRAINT [pk_Positions] PRIMARY KEY CLUSTERED
(
[batch_id] ASC,
...(more columns)
)
batch_id
和date
有一对一的关系。即,对于给定的batch_id,所有日期都相同,对于给定日期,所有batch_id都是相同的。 (我知道这是糟糕的设计。如果我要设计表格,我可能会为batch_id和日期创建一个单独的表格)batch_id
现在我想获得所有不同date
的列表。
由于表非常庞大且date
不是索引列,我不想尝试以下任何内容:
select distinct date from Batch
出于类似的原因,我已经排除了在date
上创建非聚集索引的选项
相反,我想做类似的事情:
select First(date) from Batch
Group by batch_id
或
select Top 1 date from Batch
Group by batch_id
但MS SQL不提供First()
函数,后者返回“不在聚合函数中”错误。
据我所知,我应该使用Min()
或Max()
代替First()
,例如:
select Max(date) from Batch
Group by batch_id
但是,由于有时会有超过100k的记录具有相同的batch_id
,因此使用Min()
或Max()
的效率不如仅返回第一条记录而没有任何比较。那么如何优化上一个查询以获得更好的性能呢?
答案 0 :(得分:0)
既然你说batch_id
和date
之间存在一对一的关系,那就可以胜任:
SELECT DISTINCT batch_id, date FROM Batch
如果不是这样,您可以将行号与每个记录相关联,并仅检索第一个:
WITH BatchWithRowNum AS
(
SELECT
*
, RowNum = ROW_NUMBER() OVER (PARTITION BY batch_id ORDER BY date)
FROM Batch
)
SELECT * FROM BatchWithRowNum WHERE RowNum = 1
我希望比行数方法更快的第三种方法是:
SELECT B.batch_id, T.MinDate AS date
FROM Batch B
INNER JOIN
(
SELECT B2.batch_id, MIN(B2.date) AS MinDate
FROM Batch B2
GROUP BY B2.batch_id
) T
ON B.batch_id = T.batch_id
GROUP BY B.batch_id, T.MinDate
以下通常不是一种有效的解决方案,但在您的情况下可能会有更好的性能,因为它只依赖于batch_id
上现有的索引:
SELECT
DISTINCT B.batch_id
, date = (SELECT TOP 1 date FROM Batch B2 WHERE B2.batch_id = B.batch_id)
FROM
Batch B
如果您遇到严重的性能问题并且无法添加索引,除非您使用WHERE
子句缩小结果集,否则以上任何一项都不会对您有所帮助。例如,使用一组batch-id
s或特定date
范围内的批次来引入批次的子集。
答案 1 :(得分:0)
尽管我的SQL业力很难说,但我认为这可能是迭代处理有用的一种情况。在伪代码中:
declare #WorkingTable(batchID, date)
declare @CurrentBatchID = NULL
declare @BatchDate = NULL;
select top 1
@Current BatchID = batch_id,
@BatchDate = [Date]
from Batch
where batch_id > -1 -- less than the smallest in the table
order by batch_id asc;
while @CurrentBatchID is not NULL
begin
insert #WorkingTable values (@BatchID, @BatchDate);
select top 1
@CurrentBatchID = batch_id,
@BatchDate = [Date]
from Batch
where batch_id > @CurrentBatchID
order by batch_id asc;
end
select * from #WorkingTable
虽然每次迭代将有一个表访问权限,但它将位于群集密钥上,具有带来的所有优势。但仍然很难看。
如果您打算定期执行此操作,最好创建一个只包含batch_id和[Date]的查找表,该表由ETL和清除进程维护。
答案 2 :(得分:0)
如果您创建此功能: -
CREATE FUNCTION [dbo].GetDateForBatch_id
(
@batch_id int
)
RETURNS datetime
AS
BEGIN
RETURN (SELECT TOP 1 [date]
FROM dbo.Batch
WHERE batch_id=@batch_id)
END
go
然后运行此查询: -
select
b.batch_id,
dbo.GetDateForBatch_id(b.batch_id) AS [date]
FROM (SELECT DISTINCT batch_id
FROM Batch) b
您应该使用现有的索引策略获得最佳性能。
答案 3 :(得分:0)
- 只需删除重复记录 - 最好的方法
DECLARE @juvenileid int,@ luCountyName varchar(40),@ DispHearDate datetime,@ vid int
设置@vid = 0
声明db_cursor游标
SELECT juvenileid,luCountyName,DispHearDate FROM#TEMP48 ORDER BY juvenileid
打开db_cursor
FETCH NEXT FROM db_cursor INTO @juvenileid,@ luCountyName,@ PlDt
WHILE @@ FETCH_STATUS = 0
BEGIN
BEGIN100:
如果@vid = 0
开始
SET @vid = @juvenileid
END
其他
开始
IF @ vid = @juvenileid
开始
从#TEMP48中删除juvenileid = @juvenileid
和luCountyName = @luCountyName
和DispHearDate = @DispHearDate
结束
其他
开始
SET @vid = 0
GOTO BEGIN100
END
END
FETCH NEXT FROM db_cursor INTO @juvenileid,@ luCountyName,@ DispHearDate
END
关闭db_cursor
DEALLOCATE db_cursor