In the past year or so, a few installations had begun to experience problems with the SQL Server 2005 security cache (aka TokenAndPermUserStore) growing too large over time. Some manifestations are connection and query timeouts and queries that take a long time.

The folks at PSS published the canonical blog entry about this problem, including knowledge base articles and suggestions for SQL Server 2005, and also mention of the name of the SQL Server 2008 parameters to configure the size of this cache at the end of the article.

In SQL Server 2008 the size of TokenAndPermUserStore is configurable as mentioned in the SQL Server 2008 Books Online. I happened across it yesterday trying in researching a user inquiry. The configuration options, access check cache quota and access check cache bucket count, are mentioned in the books online without much fanfare or much description. But a knowledge base article, (KB955644) published the day that SQL Server 2008 shipped, describes the defaults and suggest some guidelines for configuring these parameters. Excellent.

Categories:
SQL Server 2008

A friend of mine was asking about the affect of multi-targeting in Visual Studio 2008 on SQLCLR. For an explanation of how multi-targeting works, reference David Kean's blog entry on Visual Studio 2008 multi-targeting and FXCop.

I happened to have an instance of SQL Server 2005 RTM (which uses .NET framework version 2.0.50727.42) on hand to try. I took two assemblies as a test. Just for fun, one assembly contained a user-defined function that works on SQL Server 2005, but not on SQL Server 2008 (reference my blog posting on 'Semantic (possibly breaking) change in SQLCLR TVFs') but contains NO new 3.5-specific functionality. It simply reads the event log and returns a table in a SQLCLR TVF. One assembly used System.DateTimeOffset (a type in 2.0.50727.3053 but not in 2.0.50727.42) internally (ie, not as an input or output parameter, but inside of a method I intended to try as a SQLCLR UDF).

I compiled both assemblies on a system with Visual Studio 2008 (.NET 2.0.50727.3053) targeting the .NET Framework 3.5. As an aside, when I tried targeting .NET 2.0, running code analysis gave a warning about DateTimeOffset. Move both 3.5-targeted assemblies to my SQL Server 2005 RTM system.

The assembly with no 3.5-specific functionality cataloged and ran fine in SQL Server 2005 RTM. Attempting to catalog the assembly that included DateTimeOffset failed CREATE ASSEMBLY with the error message:

Msg 6218, Level 16, State 2, Line 1
CREATE ASSEMBLY for assembly 'UseDateTimeOffset' failed because assembly 'UseDateTimeOffset' failed verification. Check if the referenced assemblies are up-to-date and trusted (for external_access or unsafe) to execute in the database. CLR Verifier error messages if any will follow this message [ : UserDefinedFunctions::GetTimeSpan][mdToken=0x6000001] Type load failed.

where UseDateTimeOffset.dll is my assembly and UserDefinedFunctions.GetTimeSpan is the public static method that would have used it.

Hope that clarifies things. You can use 3.5-targeted assemblies on SQL Server 2005 as long as they don't use functionality (the type System.DateTimeOffset is in mscorlib.dll) that don't exist in the SQL Server 2005 machines's version of .NET.

BTW, you CAN use any of the new .NET functionality in SQL Server 2005 as long as you install .NET 3.5 on the SQL Server machine. Obviously that doesn't mean you can use DateTimeOffset as a stored procedure/UDF parameter, but you can use it inside a stored procedure called by SQLCLR. Just like you can use Array in your implementation, but not expose it to T-SQL.  I mentioned one cavaet to installing .NET 3.5 on a SQL Server 2005 machine in a previous blog posting earlier this year. Also, SQL Server 2005 SP2 won't recognize System.Core.dll as a "safe" assembly (as it is in SQL Server 2008) but that's to be expected.

Categories:
SQL Server 2008

Although being able to use a GUI tool like SQL Server Management Studio is a nice feature by itself, it's unusual that fixing something in a GUI makes a feature (that hasn't changed) more useable. The "feature" is defaults on SQLCLR procedure parameters.

You can't have defaults on parameters in .NET, but you can specify them in the CREATE PROCEDURE DDL, for example:

CREATE PROCEDURE addwithdefaults (@x int, @z int out, @y int = 5)
AS EXTERNAL NAME sampleasm.StoredProcedures.AddWithDefaults

These work just like defaults in T-SQL procedures; if you don't specify the parameter, the SQLCLR code receives the default value when it is called. Dandy...it's always worked this way.

But, in SQL Server 2005 SSMS (and SMO) the SQLCLR procedure was always displayed as "No Default". Even though there's perfectly good information in the SQL Server metadata about the default. Some folks were convinced that, even though default parameters worked as they should, it was dangerous to use them. Say a DBA was to move the procedure from test to production by scripting the CREATE PROCEDURE statement from SSMS (or SMO). They'd lose the default and when the procedure was defined with the generated script, code that worked in test (depended on the default value) would break in production.

I just noticed in SQL Server 2008 SSMS that defaults ARE displayed and procedures ARE scripted correctly. Great. Let a thousand SQLCLR procedures with default parameters bloom...I guess.

Categories:
SQL Server 2008

Extended Events is one of my favorite SQL Server 2008 features and I'll be speaking about how to use them for problem diagnosis, at the Portland (Oregon) SQL Server User's Group's September meeting. Check out http://www.pdxvbug.com/pdxuser.asp for details.

Meeting is 6:30 on Thursday Sept 25. See you there.

Categories:
SQL Server 2008

After reading Isaac's recent blog posting about spatial queries and index hinting, I thought I might add some information based on a query I was working with this week. Sometimes if you have a query that's too syntactically complex, hinting won't work. In these cases you can cause the index to be used (or at least hintable) by breaking up the query.

 

Warning. Protracted code example follows.

 

If the spatial query is somewhat complex, it's useful to write it out step by step, so we start with the query written out in steps. We're using three tables, a county table, highway table, and POI (points of interest) table. Without pondering the necessity of clipping to the county boundary twice, here's the original logic.

 

--Find all banks within 2km of I66 as it runs through Fairfax County

DECLARE @g geography

DECLARE @h geography

DECLARE @i geography

DECLARE @j geography

DECLARE @k geography

SELECT @g = geog from va where fips = 51059 -- Fairfax County

SELECT @h = geog from us_hwys where route_num = 'I66' -- I66 Hwy

SELECT @i = @h.STIntersection(@g)-- I66 within county

SELECT @j = @i.STBuffer(2000)-- buffer around I66

SELECT @k = @j.STIntersection(@g)-- clip buffer to county boundary

SELECT geog from POI

  WHERE geog.STIntersects(@k)=1 and Description = 'bank'

 

We thought that it might be better for the overall query performance to write this as a single SQL query, so, doing simple substitution, one subquery at a time, we come up with these two equivalent query sets at the end of the process:

 

-- A. Almost there... 2-query process

DECLARE @k geography

select @k =

((SELECT geog from us_hwys where route_num = 'I66').STIntersection(

  (SELECT geog from va where fips = 51059)

)).STBuffer(2000).STIntersection(

  (SELECT geog from va where fips = 51059)

)

-- uses the spatial index without a hint, total elapsed time for both steps 2 seconds

SELECT geog from POI -- with (index(spatial_idx_2))

where geog.STIntersects(@k)=1 and Description = 'bank'

go

 

-- B. Done... 1 query

-- But, doesn't use the spatial index

-- Total elapsed time, 48 minutes 53 seconds!

SELECT geog from POI  -- with (index(spatial_idx_2))  hint doesn't work

where geog.STIntersects(

  ((SELECT geog from us_hwys where route_num = 'I66').STIntersection(

    (SELECT geog from va where fips = 51059)

  )).STBuffer(2000).STIntersection(

    (SELECT geog from va where fips = 51059)

  )

)=1 and Description = 'bank'

 

The resulting query is too complex for the query processor to even "think of" a plan that uses the spatial index. Even hinting doesn't work. The simpler STIntersects query using the 2-query process can be hinted, but we don't need the hint. The query processor is smart enough to use the spatial index with the simplified version. Oh...

 

So the moral of the story is not only to be on the lookout for index-hinting opportunities, but that sometimes, if the query is too complex the query processor won't take the hint. The error in this case was:

 

Msg 8622, Level 16, State 1, Line 1

Query processor could not produce a query plan because of the hints defined in this query.

Resubmit the query without specifying any hints and without using SET FORCEPLAN.

 

In cases like this, it may be necessary to break the query into pieces in order to apply the hint. In this case, it happens with an STIntersects() that used four subqueries, the exact "complexity point" may vary with the query itself.

 

Of course, in this case, because of the repeating "clipping" steps (clip to a particular county), we can rewrite the query to use common table expressions. This not only makes it easier to read but, by removing the redundant subquery, the query processor decides to use the index with the hint.

 

WITH GetCounty as (SELECT geog from va where fips = N'51059'),

     GetHighway as(SELECT geog from us_hwys where route_num = 'I66')

SELECT POI.geog from POI with (index(spatial_idx_2)),  GetCounty C,  GetHighway H

WHERE POI.geog.STIntersects(

  H.geog.STIntersection(C.geog).STBuffer(2000).STIntersection(C.geog)

)=1 and Description = 'bank'

 

So watch out for introduction of excess complexity. Hope this was helpful.

Categories:
SQL Server 2008

Theme design by Nukeation based on Jelle Druyts