我一直在阅读文档并查看常见问题解答,但没有找到答案,这可能意味着无法完成。我的实际情况有点复杂,但我会尝试简化这个问题。对于过去几年中的每一年,我都有一个标题/详细信息表,其中包含一个链接它们的外键。年份数据在标题记录中!我希望能够查询多年来连接的所有表格。
我已经设置了遵循'SELECT + UNION ALL'格式的视图。我还在标题表上设置了检查约束,以将其值限制为各自的年份。这允许SQL Server查询优化器在运行受WHERE子句限制的查询时仅查询特定的表。真棒。到目前为止,通过搜索分区视图,可以在任何地方找到此信息。
我希望使用详细信息表进行相同类型的查询优化,但无法弄清楚。详细记录中没有任何内容表明它没有加入标题记录所属的年份;意思是,外键约束是我必须要做的唯一约束。
我想到的唯一解决方案是在详细信息表中添加'year'列,然后在查询中添加另一个where子句。有什么办法可以使用现有的外键约束来创建详细信息表的分区视图吗?
以下是一些DDL供参考:
CREATE TABLE header2008 (
hid INT PRIMARY KEY,
dt DATE CHECK ('2008-01-01' <= dt AND dt < '2009-01-01')
)
CREATE TABLE header2009 (
hid INT PRIMARY KEY,
dt DATE CHECK ('2009-01-01' <= dt AND dt < '2010-01-01')
)
CREATE TABLE detail2008 (
did INT PRIMARY KEY,
hid INT FOREIGN KEY REFERENCES header2008(hid),
value INT
)
CREATE TABLE detail2009 (
did INT PRIMARY KEY,
hid INT FOREIGN KEY REFERENCES header2009(hid),
value INT
)
GO
CREATE VIEW headerAll AS
SELECT * FROM header2008 UNION ALL
SELECT * FROM header2009
GO
CREATE VIEW detailAll AS
SELECT * FROM detail2008 UNION ALL
SELECT * FROM detail2009
GO
--This only hits the header2008 table (GOOD)
SELECT *
FROM headerAll h
WHERE dt = '2008-04-04'
--This hits the header2008, detail2008, and detail 2009 tables. (BAD)
SELECT *
FROM headerAll h
INNER JOIN detailAll d ON h.hid = d.hid
WHERE dt = '2008-04-04'
答案 0 :(得分:0)
由于您不打算使用分区表,我假设您无法定位2005+企业版或更高版本。
以下是向表中添加新物理列的替代方法:
CREATE VIEW detailAll AS
SELECT 2008 AS Year, * FROM detail2008
UNION ALL
SELECT 2009, * FROM detail2009
然后,
SELECT *
FROM headerAll h
INNER JOIN detailAll d ON h.hid = d.hid
WHERE dt = '2008-04-04' AND d.Year = 2008
在你跑掉并实施之前,有一个问题;好吧,实际上有两次捕获。
此解决方案与编写的headerAll
视图一样,无法容纳分区列上的参数,仍然可以进行分区消除。使用WHERE dt = @date AND d.Year = YEAR(@date)
的搜索谓词会导致两个视图中所有表的表扫描,因为查询优化器假定@date
是一个任意值(并且没有办法解决这个问题)。如果视图在您的数据库API中公开公开,这是一个性能灾难的方法:查询中的参数化没有限制,并且大多数查询作者和ORM倾向于尽可能使用参数化查询(这几乎总是一件好事!)
要使视图在实际应用程序中执行分区消除,您将不得不求助于动态字符串执行。如何实现这一点取决于您的业务需求,数据要求和应用程序架构。如果你从多年来抓取数据,那将会有点棘手。
另请注意,使用动态字符串执行将允许您直接针对基表编写查询,而不是为每个“表”引入UNION
ed视图。我不认为后者有什么问题,但这是你可能没有考虑的选择。