我有一个仅由自动增量列索引的大表,该列还填充了当前时间戳(未编入索引)。
CREATE TABLE MyTable
(
ID BIGINT NOT NULL IDENTITY(1, 1) PRIMARY KEY
,AuditTimestampUtc DATETIME NOT NULL DEFAULT(GETUTCDATE())
,...
)
Run Code Online (Sandbox Code Playgroud)
如果我需要通过行的创建时间戳来查询,我该如何高效地进行查询?添加索引是不可行的,因为表非常庞大(数亿到数十亿行),因为我们无法承受停机时间,而且我正在只读环境中执行罕见的调试任务,这本质上是
SELECT [...] FROM MyTable WHERE AuditTimestampUtc BETWEEN @Start AND @End
Run Code Online (Sandbox Code Playgroud)
我正在尝试调试一个新问题,之前没有做过这个任务,所以我很难提出创建新索引的论点。不幸的是,处理创建和清理完整数据库转储(特别是考虑到其大小)或将其克隆到另一个环境的请求的过程相当多。我有一个过时的转储要试验,但运行最终查询将通过生产中的只读帐户进行监督。
编写自定义二进制搜索似乎有点过头了,尤其是在 RDBMS 中,但唉计算机不是读心者,即使对于一个人来说,身份列可以用作代理排序* 以通过创建有效地搜索表,这是显而易见的时间。
*假设没有人能够IDENTITY_INSERT
违反这个时间顺序保证。
PS 我不相信数据库平台第一次与这个问题非常相关(忽略声明索引/默认约束/等的特定语法差异),但我使用的是 SQL Server。
您可以创建一个仅包含您感兴趣的两列的临时表,使用键列作为指向“真实”表的指针。就像是:
CREATE TABLE #t
(
ID int NOT NULL
, AuditTimestampUtc datetime NOT NULL
);
Run Code Online (Sandbox Code Playgroud)
像这样从 MyTable 插入行:
INSERT INTO #t WITH (TABLOCKX) (ID, AuditTimeStampUtc)
SELECT mt.ID
, mt.AuditTimeStampUtc
FROM dbo.MyTable mt
Run Code Online (Sandbox Code Playgroud)
然后在表上创建一个索引,如下所示:
CREATE CLUSTERED INDEX t_AuditTimeStampUtc
ON #t (AuditTimeStampUtc);
Run Code Online (Sandbox Code Playgroud)
现在,您应该能够使用 #temp 表上的索引查询“真实”表,如下所示:
SELECT <columns from mt>
FROM dbo.MyTable mt
INNER JOIN #t t ON mt.ID = t.ID
WHERE t.AuditTimeStampUtc >= '2019-06-01 00:00:00'
AND t.AuditTimeStampUtc < '2019-07-01 00:00:00'
Run Code Online (Sandbox Code Playgroud)
上面的查询可能会在非聚集索引上执行索引查找t_AuditTimeStampUtc
,并使用嵌套循环连接到 MyTable。这可能比仅查询原始表要快。特别是如果您需要对MyTable
.
从大表复制数据似乎是个坏主意。如果原始表只有两列,那么是的,我同意这是一件愚蠢的事情。但是,如果MyTable
有很多列,临时表只会占用主表空间的一小部分,效率会更高。