【发布时间】:2019-08-06 21:54:21
【问题描述】:
我有两个表,都包含数百万行数据。
tbl_one:
purchasedtm DATETIME,
userid INT,
totalcost INT
tbl_two:
id BIGINT,
eventdtm DATETIME,
anothercol INT
第一个表的前两列有一个聚集索引:CLUSTERED INDEX tbl_one_idx ON(purchasedtm, userid)
第二个在其 ID 列上有一个主键,在 eventdtm 列上也有一个非聚集索引。
我想运行一个查询来查找purchasedtm 和eventdtm 在同一天的行。
最初,我将查询写为:
WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE)
但这不会使用两个索引中的任何一个。
后来,我将查询更改为:
WHERE tbl_one.purchasedtm >= CAST(tbl_two.eventdtm AS DATE)
AND tbl_one.purchasedtm < DATEADD(DAY, 1, CAST(tbl_two.eventdtm AS DATE))
这样,因为只有比较的一侧被包裹在一个函数中,另一侧仍然可以使用它的索引。对吗?
我还有一些其他问题:
- 我也可以用另一种方式编写查询,即保持
tbl_two.eventdtm不变并将tbl_one.purchasedtm包装在CAST()中。这会对性能产生影响吗? - 如果上一个问题的答案是肯定的,是不是因为
eventdtm有自己的专用索引,而查找purcahsedtm只会是部分索引匹配? - 在决定这两种选择中哪一种更好时,我还可以考虑其他因素吗? (例如,如果
tbl_one有数百万行,而tbl_two有数十亿行,这会影响我应该 CAST 哪一列,不应该 CAST 哪一列?) - 一般来说,如果您比较两个都被索引的列,与只有其中一个被索引的类似情况相比,我们是否会获得任何性能?
- 最后,我可以在不使用 CAST 的情况下执行我的原始任务吗?
注意:我没有创建或修改索引、添加列等的能力。
【问题讨论】:
-
WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE)“但这不会使用两个索引中的任何一个。” 错误。CAST([column] AS date)是 SARGable/ SARGable functions in SQL Server -
理想情况下,用户 ID 将是表 1 的 PK,并且您将拥有另一个包含所有购买的表。你在 IT 领域加入这些吗?如果是这样,交换该集群键的顺序会有所帮助。
-
您修改后的查询是否使用了索引?
-
@Larnu 我不知道!很有意思。我会阅读更多内容并更新我的问题。但是你能在非 SARGable 的上下文中回应它吗? (例如,如果我使用的 CAST 不是 SRGable,或者不是 CAST 的函数)
-
大部分时间将 any 函数应用于
WHERE中的列将使其不可搜索。我能想到的唯一一个实际上是 SARGable 是CAST({column},AS date)。我不记得我的头顶,但我认为CONVERT(int,DecimalColumn)是SARGable。你(我)看到的最常见的东西是WHERE ISNULL(MyColumn,0) = ISNULL(@MyVariable,0)之类的东西,它不是 SARGable。使用布尔逻辑WHERE (MyColumn = @MyVariable OR (MyColumn IS NULL AND @MyVariable IS NULL))编写类似的东西会更好。
标签: sql-server datetime indexing casting sql-server-2016