使用从linq到sql查询的校验和索引

时间:2017-07-21 08:06:25

标签: c# sql-server linq linq-to-sql

我使用CHECKSUM()作为计算列,在nvarchar(MAX) - 列上有一个索引表。 SQL查询可以使用带有文本值及其校验和的WHERE - 子句来使用此索引。

查询如何使用此索引?

我查看了sqlfunctions.checksum of linq objectHow do I calculate a checksum on all columns in a row using LINQ and Entity Framework?及其答案,即SqlFunctions.Checksum("important"),以获得单个值的校验和。
SqlFunctions.Checksum("important")抛出异常:

  

此功能只能从LINQ to Entities

调用

(此行为与Checksum(string))文档中记录的完全相同。

中,表格可以通过以下方式定义:

CREATE TABLE [Tags](
    [TagId] [uniqueidentifier] NOT NULL PRIMARY KEY,
    [Tag] [nvarchar](max) NOT NULL,
    [TagHash] AS (checksum([Tag])) PERSISTED
 )

和索引通过:

 CREATE INDEX [IX_Tags] ON [Tags] (
     [TagHash] ASC
 )

以下SQL查询可能使用索引 1

SELECT * FROM [Tags]
WHERE [TagHash] = checksum('Important') AND
    [Tag] = 'Important'

中的此查询表达式尝试会引发NotSupportedException

from tag in Tags
where SqlFunctions.Checksum("important") == tag.Hash &&
    "important" == tag.Tag
select tag

如何在中构建上述查询而不使用这样的SqlFunctions.Checksum(string)构造?

1) 这取决于查询优化器。

2 个答案:

答案 0 :(得分:1)

如果您可以修改数据库并更改Linq2Sql模型,那么您可以通过创建自己的包装CheckSum的sql函数来完成此操作。例如

Create FUNCTION dbo.MyCheckSum (@input NVarChar(max)) RETURNS int
AS
BEGIN   
   Declare @output int
   select @output = CheckSum(@input)
   return @output
End

然后你就可以使用它了。

from tag in Tags
where MyChecksum("important") == tag.Hash && "important" == tag.Tag
select tag

如果您无法修改数据库或模型,则可以使用适用于您的示例的解决方法,但会牺牲另一个数据库命中,例如

int checkSum this dc.ExecuteQuery<int>("select Checksum('important')").Single(); 

from tag in Tags
where checkSum == tag.Hash &&   "important" == tag.Tag
select tag

答案 1 :(得分:0)

而不是围绕CHECKSUM编写通用包装(作为sgmoore suggests)。

您可以编写一个访问器函数来通过校验和索引访问该表:

CREATE FUNCTION TagsByName(
     @key nvarchar(max))
RETURNS TABLE
AS
RETURN SELECT
    [TagId],
    [Tag],
    [TagHash]
FROM Tags
WHERE CHECKSUM(@key) = [TagHash] AND
    @key = [Tag];

sgmoore's solution相比,这样做的好处是所有 - 和SQL查询都可以通过TVF访问该表,并且不使用索引和校验和。缺点是每个校验和索引构造都需要自己的TVF,而在sgmoore's solution中,单个TVF就足够了。