我有一个VS2010项目,其中包含从SQL 2008数据库生成的Linq到SQL类。相关表有一个特殊的Created列,该列的类型为datetimeoffset(3),每天用作分区键:
CREATE TABLE [dbo].[tableA](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Created] [datetimeoffset](3) NOT NULL,
[A] [int] NULL,
CONSTRAINT [PK_TableA] PRIMARY KEY CLUSTERED
(
[Created] ASC,
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) on partScheme_Daily_OnCreatedDate (Created)
) on partScheme_Daily_OnCreatedDate (Created)
为此列生成的linq-to-SQL代码将DateTimeOffset显示为其类型。
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.TableA")]
public partial class TableA : INotifyPropertyChanging, INotifyPropertyChanged {
private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
private int _Id;
private System.DateTimeOffset _Created;
etc
我可以基于生成的类创建并执行linq-to-sql查询。
var query = db.TableA.Where(pt => pt.Created >= (DateTimeOffset) startTime && pt.Created <= endTime
这将转换为正确的SQL查询,但SQL端的类型为DateTimeOffset(7)。因此,数据库不使用最佳分区消除,而是访问所有分区。如果我根据捕获的SQL查询更改类型DateTimeOffset(3)并在SSMS中执行,它将使用分区消除。
exec sp_executesql N'SELECT TOP (10001) [t0].[Id], [t0].[Created],
FROM [dbo].[TableA] AS [t0]
WHERE ([t0].[Created] >= @p0) AND ([t0].[Created] <= @p1)
ORDER BY [t0].[Created] DESC',N'@p0 datetimeoffset(3),@p1 datetimeoffset(3)',@p0='2015-02-27 23:00:00 +00:00',@p1='2015-03-03 22:59:59 +00:00'
那么如何获得最优分区消除呢?在我的示例中,我最多需要访问2个分区。
我曾想过创建一个存储过程,但这意味着我失去了在c#代码中轻松更改查询的灵活性。另一个解决方案是将Created列的SQL类型更改为DateTimeOffset(7)。但这样做的缺点是存储冗余的精度数据,而我实际上没有这些数据。
我想听听其他的可能性,要么通过指示linq将DateTimeOffset(3)作为sql变量类型进行sql生成,要么通过另一种方式使分区消除变得高效。
附言:我已经简化了表格定义和查询的简短问题定义。
根据需要使用DateTimeOffset.ToString格式。
DateTimeOffset outputDate = new DateTimeOffset(2007, 11, 1, 9, 0, 0,
new TimeSpan(-7, 0, 0));
string format = "dddd, MMM dd yyyy HH:mm:ss zzz";
// Output date and time using custom format specification
Console.WriteLine(outputDate.ToString(format, null as DateTimeFormatInfo));
Console.WriteLine(outputDate.ToString(format, CultureInfo.InvariantCulture));
Console.WriteLine(outputDate.ToString(format,
new CultureInfo("fr-FR")));
Console.WriteLine(outputDate.ToString(format,
new CultureInfo("es-ES")));
// The example displays the following output to the console:
// Thursday, Nov 01 2007 09:00:00 -07:00
// Thursday, Nov 01 2007 09:00:00 -07:00
// jeudi, nov. 01 2007 09:00:00 -07:00
// jueves, nov 01 2007 09:00:00 -07:00