0

I have a table with an index on a nvarchar(MAX)-column by using CHECKSUM() as a computed column. SQL query can use this index by using a WHERE-clause with both the text value and its checksum.

How can a query use this index?

I looked at sqlfunctions.checksum of linq object and How do I calculate a checksum on all columns in a row using LINQ and Entity Framework? and their answers, i.e SqlFunctions.Checksum("important") for a checksum of a single value.
But SqlFunctions.Checksum("important") throws the exception:

This function can only be invoked from LINQ to Entities

(this behaviour is exactly as is documented in the documentation for Checksum(string)).

In the table can be defined via:

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

and the index via:

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

The following SQL query might use the index1:

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

This query expression attempt in throws the NotSupportedException:

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

How can the above query be constructed in without using only constructs like SqlFunctions.Checksum(string)?


1) It depends on the query optimizer.

2 Answers 2

1

If you can modify your database and change your Linq2Sql model then you can do this by creating your own sql function that wraps CheckSum. For example

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

You can then use this like.

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

If you can't modify your database or model, you could have a workaround that works for your example, at the expense of another database hit, eg

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

from tag in Tags
where checkSum == tag.Hash &&   "important" == tag.Tag
select tag
Sign up to request clarification or add additional context in comments.

Comments

0

Instead of writing a generic wrapper around CHECKSUM (as sgmoore suggests).

You can write an accessor function to access the table via the checksum index:

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

Compared to sgmoore's solution this has the advantage that all - and SQL-queries can access the table via the TVF and are insulated from using the index and the checksums. The downside is that every checksum index construct requires its own TVF, whereas in sgmoore's solution a single TVF suffices.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.