Apparently, my CLR assembly function is causing deadlocks?Merge causing deadlocks`ON CONFLICT DO UPDATE` causing deadlocks?Audit use of CLR Table-valued functionCan add one CLR function to SQL server but not a second in the same assembly: loading wrong DLLAssembly is not authorized for PERMISSION_SET=UNSAFE when creating a CLR assemblyIs there a way to prevent Scalar UDFs in computed columns from inhibiting parallelism?Which CLR Stored Proc is causing memory pressure leading to sqlservr.exe terminating unexpectedly?Why is this seemingly simple insert trigger function causing deadlocks?SQL Function, get value to send to CLRAdded .Net assembly to SQL CLR without turning TRUSTWORTHY ON

Mistake in years of experience in resume?

constexpr member function with std::vector data member in C++

What term is being referred to with "reflected-sound-of-underground-spirits"?

Read line from file and process something

Pre-plastic human skin alternative

Is Diceware more secure than a long passphrase?

'It addicted me, with one taste.' Can 'addict' be used transitively?

What happens in the secondary winding if there's no spark plug connected?

Pulling the rope with one hand is as heavy as with two hands?

Can an Area of Effect spell cast outside a Prismatic Wall extend inside it?

Why does Mind Blank stop the Feeblemind spell?

Why do games have consumables?

Why did C use the -> operator instead of reusing the . operator?

Is the claim "Employers won't employ people with no 'social media presence'" realistic?

"The cow" OR "a cow" OR "cows" in this context

Two field separators (colon and space) in awk

How does Captain America channel this power?

Checks user level and limit the data before saving it to mongoDB

How do I reattach a shelf to the wall when it ripped out of the wall?

Was there a Viking Exchange as well as a Columbian one?

Why didn't the Space Shuttle bounce back into space as many times as possible so as to lose a lot of kinetic energy up there?

What happens to Mjolnir (Thor's hammer) at the end of Endgame?

Was there a shared-world project before "Thieves World"?

Re-entry to Germany after vacation using blue card



Apparently, my CLR assembly function is causing deadlocks?


Merge causing deadlocks`ON CONFLICT DO UPDATE` causing deadlocks?Audit use of CLR Table-valued functionCan add one CLR function to SQL server but not a second in the same assembly: loading wrong DLLAssembly is not authorized for PERMISSION_SET=UNSAFE when creating a CLR assemblyIs there a way to prevent Scalar UDFs in computed columns from inhibiting parallelism?Which CLR Stored Proc is causing memory pressure leading to sqlservr.exe terminating unexpectedly?Why is this seemingly simple insert trigger function causing deadlocks?SQL Function, get value to send to CLRAdded .Net assembly to SQL CLR without turning TRUSTWORTHY ON






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








6















Our application needs to work equally well with an Oracle database or a Microsoft SQL Server database. To facilitate this, we created a handful of UDFs to homogenize our query syntax. For example, SQL Server has GETDATE() and Oracle has SYSDATE. They perform the same function but they are different words. We wrote a wrapper UDF called NOW() for both platforms which wraps the relevant platform specific syntax in a common function name. We have other such functions, some of which do essentially nothing but exist solely for the sake of homogenization. Unfortunately, this has a cost for SQL Server. Inline scalar UDFs wreak havoc on performance and completely disable parallelism. As an alternative, we wrote CLR assembly functions to accomplish the same goals. When we deployed this to a client they started experiencing frequent deadlocks. This particular client is using replication and high availability techniques and I'm wondering if there's some sort of interaction going on here. I just don't understand how introducing a CLR function would cause problems like this. For reference, I've included the original scalar UDF definition as well as the replacement CLR definition in C# and the SQL declaration for it. I also have deadlock XML that I can provide if that helps.



Original UDF



CREATE FUNCTION [fn].[APAD]
(
@Value VARCHAR(4000)
, @tablename VARCHAR(4000) = NULL
, @columnname VARCHAR(4000) = NULL
)

RETURNS VARCHAR(4000)
WITH SCHEMABINDING
AS

BEGIN
RETURN LTRIM(RTRIM(@Value))
END
GO


CLR Assembly Function



[SqlFunction(IsDeterministic = true)]
public static string APAD(string value, string tableName, string columnName)

return value?.Trim();



SQL Server Declaration for CLR Function



CREATE FUNCTION [fn].[APAD]
(
@Value NVARCHAR(4000),
@TableName NVARCHAR(4000),
@ColumnName NVARCHAR(4000)
) RETURNS NVARCHAR(4000)
AS
EXTERNAL NAME ASI.fn.APAD
GO









share|improve this question









New contributor




Russ Suter is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.















  • 9





    Deterministic scalar CLR functions should not contribute to deadlocks. Of course CLR functions that read the database might. You should include the deadlock XML in your question.

    – David Browne - Microsoft
    5 hours ago

















6















Our application needs to work equally well with an Oracle database or a Microsoft SQL Server database. To facilitate this, we created a handful of UDFs to homogenize our query syntax. For example, SQL Server has GETDATE() and Oracle has SYSDATE. They perform the same function but they are different words. We wrote a wrapper UDF called NOW() for both platforms which wraps the relevant platform specific syntax in a common function name. We have other such functions, some of which do essentially nothing but exist solely for the sake of homogenization. Unfortunately, this has a cost for SQL Server. Inline scalar UDFs wreak havoc on performance and completely disable parallelism. As an alternative, we wrote CLR assembly functions to accomplish the same goals. When we deployed this to a client they started experiencing frequent deadlocks. This particular client is using replication and high availability techniques and I'm wondering if there's some sort of interaction going on here. I just don't understand how introducing a CLR function would cause problems like this. For reference, I've included the original scalar UDF definition as well as the replacement CLR definition in C# and the SQL declaration for it. I also have deadlock XML that I can provide if that helps.



Original UDF



CREATE FUNCTION [fn].[APAD]
(
@Value VARCHAR(4000)
, @tablename VARCHAR(4000) = NULL
, @columnname VARCHAR(4000) = NULL
)

RETURNS VARCHAR(4000)
WITH SCHEMABINDING
AS

BEGIN
RETURN LTRIM(RTRIM(@Value))
END
GO


CLR Assembly Function



[SqlFunction(IsDeterministic = true)]
public static string APAD(string value, string tableName, string columnName)

return value?.Trim();



SQL Server Declaration for CLR Function



CREATE FUNCTION [fn].[APAD]
(
@Value NVARCHAR(4000),
@TableName NVARCHAR(4000),
@ColumnName NVARCHAR(4000)
) RETURNS NVARCHAR(4000)
AS
EXTERNAL NAME ASI.fn.APAD
GO









share|improve this question









New contributor




Russ Suter is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.















  • 9





    Deterministic scalar CLR functions should not contribute to deadlocks. Of course CLR functions that read the database might. You should include the deadlock XML in your question.

    – David Browne - Microsoft
    5 hours ago













6












6








6








Our application needs to work equally well with an Oracle database or a Microsoft SQL Server database. To facilitate this, we created a handful of UDFs to homogenize our query syntax. For example, SQL Server has GETDATE() and Oracle has SYSDATE. They perform the same function but they are different words. We wrote a wrapper UDF called NOW() for both platforms which wraps the relevant platform specific syntax in a common function name. We have other such functions, some of which do essentially nothing but exist solely for the sake of homogenization. Unfortunately, this has a cost for SQL Server. Inline scalar UDFs wreak havoc on performance and completely disable parallelism. As an alternative, we wrote CLR assembly functions to accomplish the same goals. When we deployed this to a client they started experiencing frequent deadlocks. This particular client is using replication and high availability techniques and I'm wondering if there's some sort of interaction going on here. I just don't understand how introducing a CLR function would cause problems like this. For reference, I've included the original scalar UDF definition as well as the replacement CLR definition in C# and the SQL declaration for it. I also have deadlock XML that I can provide if that helps.



Original UDF



CREATE FUNCTION [fn].[APAD]
(
@Value VARCHAR(4000)
, @tablename VARCHAR(4000) = NULL
, @columnname VARCHAR(4000) = NULL
)

RETURNS VARCHAR(4000)
WITH SCHEMABINDING
AS

BEGIN
RETURN LTRIM(RTRIM(@Value))
END
GO


CLR Assembly Function



[SqlFunction(IsDeterministic = true)]
public static string APAD(string value, string tableName, string columnName)

return value?.Trim();



SQL Server Declaration for CLR Function



CREATE FUNCTION [fn].[APAD]
(
@Value NVARCHAR(4000),
@TableName NVARCHAR(4000),
@ColumnName NVARCHAR(4000)
) RETURNS NVARCHAR(4000)
AS
EXTERNAL NAME ASI.fn.APAD
GO









share|improve this question









New contributor




Russ Suter is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.












Our application needs to work equally well with an Oracle database or a Microsoft SQL Server database. To facilitate this, we created a handful of UDFs to homogenize our query syntax. For example, SQL Server has GETDATE() and Oracle has SYSDATE. They perform the same function but they are different words. We wrote a wrapper UDF called NOW() for both platforms which wraps the relevant platform specific syntax in a common function name. We have other such functions, some of which do essentially nothing but exist solely for the sake of homogenization. Unfortunately, this has a cost for SQL Server. Inline scalar UDFs wreak havoc on performance and completely disable parallelism. As an alternative, we wrote CLR assembly functions to accomplish the same goals. When we deployed this to a client they started experiencing frequent deadlocks. This particular client is using replication and high availability techniques and I'm wondering if there's some sort of interaction going on here. I just don't understand how introducing a CLR function would cause problems like this. For reference, I've included the original scalar UDF definition as well as the replacement CLR definition in C# and the SQL declaration for it. I also have deadlock XML that I can provide if that helps.



Original UDF



CREATE FUNCTION [fn].[APAD]
(
@Value VARCHAR(4000)
, @tablename VARCHAR(4000) = NULL
, @columnname VARCHAR(4000) = NULL
)

RETURNS VARCHAR(4000)
WITH SCHEMABINDING
AS

BEGIN
RETURN LTRIM(RTRIM(@Value))
END
GO


CLR Assembly Function



[SqlFunction(IsDeterministic = true)]
public static string APAD(string value, string tableName, string columnName)

return value?.Trim();



SQL Server Declaration for CLR Function



CREATE FUNCTION [fn].[APAD]
(
@Value NVARCHAR(4000),
@TableName NVARCHAR(4000),
@ColumnName NVARCHAR(4000)
) RETURNS NVARCHAR(4000)
AS
EXTERNAL NAME ASI.fn.APAD
GO






sql-server functions deadlock sql-clr scalar-function






share|improve this question









New contributor




Russ Suter is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




Russ Suter is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 4 hours ago









Solomon Rutzky

49.9k585184




49.9k585184






New contributor




Russ Suter is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 5 hours ago









Russ SuterRuss Suter

311




311




New contributor




Russ Suter is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Russ Suter is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Russ Suter is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







  • 9





    Deterministic scalar CLR functions should not contribute to deadlocks. Of course CLR functions that read the database might. You should include the deadlock XML in your question.

    – David Browne - Microsoft
    5 hours ago












  • 9





    Deterministic scalar CLR functions should not contribute to deadlocks. Of course CLR functions that read the database might. You should include the deadlock XML in your question.

    – David Browne - Microsoft
    5 hours ago







9




9





Deterministic scalar CLR functions should not contribute to deadlocks. Of course CLR functions that read the database might. You should include the deadlock XML in your question.

– David Browne - Microsoft
5 hours ago





Deterministic scalar CLR functions should not contribute to deadlocks. Of course CLR functions that read the database might. You should include the deadlock XML in your question.

– David Browne - Microsoft
5 hours ago










1 Answer
1






active

oldest

votes


















4














What version(s) of SQL Server are you using?



I do recall seeing a slight change in behavior in SQL Server 2017 not too long ago. I will have to go back and see if I can find where I made a note of it, but I think it had to do with a schema lock being initiated when a SQLCLR object was being accessed.



While I am looking for that, I will say the following regarding your approach:



  1. Please use the Sql* types for input parameters, return types. You should be using SqlString instead of string. SqlString is very similar to a nullable string (your value?, but it has other functionality built in that is SQL Server-specific. All of the Sql* types have a Value property that returns the expected .NET type (e.g. SqlString.Value returns string, SqlInt32 returns int, SqlDateTime returns DateTime, etc).


  2. I would recommend against this entire approach to begin with, whether or not the deadlocks are related. I say this because:



    1. Even with deterministic SQLCLR UDFs being able to participate in parallel plans, you are most likely going to get performance hits for emulating simplistic built-in functions.

    2. The SQLCLR API does not allow for VARCHAR. Are you ok with implicitly converting everything to NVARCHAR and then again back to VARCHAR for simple operations?

    3. The SQLCLR API does not allow for overloading, so you might need multiple versions of functions that do allow for different signatures in T-SQL and/or PL/SQL.

    4. Similar to not allowing for overloading, there is a big difference between NVARCHAR(4000) and NVARCHAR(MAX): the MAX type (having even a single one of them in the signature) make the SQLCLR call take twice as long as not having any MAX type in the signature (I believe this holds true for VARBINARY(MAX) vs VARBINARY(4000) as well). So, you need to decide between:

      • using only NVARCHAR(MAX) to have a simplified API, but take the performance hit when you are using 8000 bytes or less of string data, or

      • creating two variations for all / most / many string functions: one with MAX types, and one without (for when you are guaranteed to never go over 8000 bytes of string data in or out). This is the approach I chose to take for most of the functions in my SQL# library: there is a Trim() function which likely has one or more MAX types, and a Trim4k() version which never has a MAX type anywhere in the signature or result set schema. The "4k" versions are absolutely more efficient.



    5. You are not being careful to emulate functionality given the example in the question. LTRIM and RTRIM only trim spaces, while .NET String.Trim() trims white space (at least space, tabs, and newlines). For example:



       PRINT LTRIM(RTRIM(N' a '));


    6. Also, I just noticed that your function, both in T-SQL and in C#, only uses 1 of the 3 input parameters. Is this just a proof of concept, or redacted code?






share|improve this answer

























  • 1. Thanks for the tip on using the Sql types. I'll make that change now. 2. There are external forces at work here which necessitate the use of them. I'm not thrilled about it but trust me, it's better than the alternative. My original question contains a little bit of the explanation as to why a seemingly asinine function exists and is being used.

    – Russ Suter
    4 hours ago












  • @RussSuter Understood re: external forces. I was just pointing out some pitfalls that might not have been known when that decision was made. Either way, I'm unable to find my notes or reproduce the scenario from the few details I remember of it. I just remember something definitely changing in 2017 with regards to transactions and calling code from an assembly, and being really annoyed with it as it seemed like a needless change for the worse, and I had to work around it for what I was testing that worked fine in prior versions. So, please post a link in the question to the deadlock XML.

    – Solomon Rutzky
    3 hours ago











  • Thanks for that additional info. Here's a link to the XML: dropbox.com/s/n9w8nsdojqdypqm/deadlock17.xml?dl=0

    – Russ Suter
    2 hours ago











  • @RussSuter Have you tried this with inlining the T-SQL? Looking at the deadlock XML (which is not easy as it's a single line--all newlines got removed somehow) it appears to be a series of PAGE locks between sessions 60 and 78. There are 8 pages locked between both sessions: 3 for one SPID and 5 for the other. Each with a different process ID, so this is an issue of parallelism. If this is related to SQLCLR, it might ironically be the fact that SQLCLR isn't preventing parallelism. This is why I asked if you have tried putting the simple function inline as that might also show the deadlock.

    – Solomon Rutzky
    1 hour ago











Your Answer








StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "182"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);






Russ Suter is a new contributor. Be nice, and check out our Code of Conduct.









draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f236794%2fapparently-my-clr-assembly-function-is-causing-deadlocks%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









4














What version(s) of SQL Server are you using?



I do recall seeing a slight change in behavior in SQL Server 2017 not too long ago. I will have to go back and see if I can find where I made a note of it, but I think it had to do with a schema lock being initiated when a SQLCLR object was being accessed.



While I am looking for that, I will say the following regarding your approach:



  1. Please use the Sql* types for input parameters, return types. You should be using SqlString instead of string. SqlString is very similar to a nullable string (your value?, but it has other functionality built in that is SQL Server-specific. All of the Sql* types have a Value property that returns the expected .NET type (e.g. SqlString.Value returns string, SqlInt32 returns int, SqlDateTime returns DateTime, etc).


  2. I would recommend against this entire approach to begin with, whether or not the deadlocks are related. I say this because:



    1. Even with deterministic SQLCLR UDFs being able to participate in parallel plans, you are most likely going to get performance hits for emulating simplistic built-in functions.

    2. The SQLCLR API does not allow for VARCHAR. Are you ok with implicitly converting everything to NVARCHAR and then again back to VARCHAR for simple operations?

    3. The SQLCLR API does not allow for overloading, so you might need multiple versions of functions that do allow for different signatures in T-SQL and/or PL/SQL.

    4. Similar to not allowing for overloading, there is a big difference between NVARCHAR(4000) and NVARCHAR(MAX): the MAX type (having even a single one of them in the signature) make the SQLCLR call take twice as long as not having any MAX type in the signature (I believe this holds true for VARBINARY(MAX) vs VARBINARY(4000) as well). So, you need to decide between:

      • using only NVARCHAR(MAX) to have a simplified API, but take the performance hit when you are using 8000 bytes or less of string data, or

      • creating two variations for all / most / many string functions: one with MAX types, and one without (for when you are guaranteed to never go over 8000 bytes of string data in or out). This is the approach I chose to take for most of the functions in my SQL# library: there is a Trim() function which likely has one or more MAX types, and a Trim4k() version which never has a MAX type anywhere in the signature or result set schema. The "4k" versions are absolutely more efficient.



    5. You are not being careful to emulate functionality given the example in the question. LTRIM and RTRIM only trim spaces, while .NET String.Trim() trims white space (at least space, tabs, and newlines). For example:



       PRINT LTRIM(RTRIM(N' a '));


    6. Also, I just noticed that your function, both in T-SQL and in C#, only uses 1 of the 3 input parameters. Is this just a proof of concept, or redacted code?






share|improve this answer

























  • 1. Thanks for the tip on using the Sql types. I'll make that change now. 2. There are external forces at work here which necessitate the use of them. I'm not thrilled about it but trust me, it's better than the alternative. My original question contains a little bit of the explanation as to why a seemingly asinine function exists and is being used.

    – Russ Suter
    4 hours ago












  • @RussSuter Understood re: external forces. I was just pointing out some pitfalls that might not have been known when that decision was made. Either way, I'm unable to find my notes or reproduce the scenario from the few details I remember of it. I just remember something definitely changing in 2017 with regards to transactions and calling code from an assembly, and being really annoyed with it as it seemed like a needless change for the worse, and I had to work around it for what I was testing that worked fine in prior versions. So, please post a link in the question to the deadlock XML.

    – Solomon Rutzky
    3 hours ago











  • Thanks for that additional info. Here's a link to the XML: dropbox.com/s/n9w8nsdojqdypqm/deadlock17.xml?dl=0

    – Russ Suter
    2 hours ago











  • @RussSuter Have you tried this with inlining the T-SQL? Looking at the deadlock XML (which is not easy as it's a single line--all newlines got removed somehow) it appears to be a series of PAGE locks between sessions 60 and 78. There are 8 pages locked between both sessions: 3 for one SPID and 5 for the other. Each with a different process ID, so this is an issue of parallelism. If this is related to SQLCLR, it might ironically be the fact that SQLCLR isn't preventing parallelism. This is why I asked if you have tried putting the simple function inline as that might also show the deadlock.

    – Solomon Rutzky
    1 hour ago















4














What version(s) of SQL Server are you using?



I do recall seeing a slight change in behavior in SQL Server 2017 not too long ago. I will have to go back and see if I can find where I made a note of it, but I think it had to do with a schema lock being initiated when a SQLCLR object was being accessed.



While I am looking for that, I will say the following regarding your approach:



  1. Please use the Sql* types for input parameters, return types. You should be using SqlString instead of string. SqlString is very similar to a nullable string (your value?, but it has other functionality built in that is SQL Server-specific. All of the Sql* types have a Value property that returns the expected .NET type (e.g. SqlString.Value returns string, SqlInt32 returns int, SqlDateTime returns DateTime, etc).


  2. I would recommend against this entire approach to begin with, whether or not the deadlocks are related. I say this because:



    1. Even with deterministic SQLCLR UDFs being able to participate in parallel plans, you are most likely going to get performance hits for emulating simplistic built-in functions.

    2. The SQLCLR API does not allow for VARCHAR. Are you ok with implicitly converting everything to NVARCHAR and then again back to VARCHAR for simple operations?

    3. The SQLCLR API does not allow for overloading, so you might need multiple versions of functions that do allow for different signatures in T-SQL and/or PL/SQL.

    4. Similar to not allowing for overloading, there is a big difference between NVARCHAR(4000) and NVARCHAR(MAX): the MAX type (having even a single one of them in the signature) make the SQLCLR call take twice as long as not having any MAX type in the signature (I believe this holds true for VARBINARY(MAX) vs VARBINARY(4000) as well). So, you need to decide between:

      • using only NVARCHAR(MAX) to have a simplified API, but take the performance hit when you are using 8000 bytes or less of string data, or

      • creating two variations for all / most / many string functions: one with MAX types, and one without (for when you are guaranteed to never go over 8000 bytes of string data in or out). This is the approach I chose to take for most of the functions in my SQL# library: there is a Trim() function which likely has one or more MAX types, and a Trim4k() version which never has a MAX type anywhere in the signature or result set schema. The "4k" versions are absolutely more efficient.



    5. You are not being careful to emulate functionality given the example in the question. LTRIM and RTRIM only trim spaces, while .NET String.Trim() trims white space (at least space, tabs, and newlines). For example:



       PRINT LTRIM(RTRIM(N' a '));


    6. Also, I just noticed that your function, both in T-SQL and in C#, only uses 1 of the 3 input parameters. Is this just a proof of concept, or redacted code?






share|improve this answer

























  • 1. Thanks for the tip on using the Sql types. I'll make that change now. 2. There are external forces at work here which necessitate the use of them. I'm not thrilled about it but trust me, it's better than the alternative. My original question contains a little bit of the explanation as to why a seemingly asinine function exists and is being used.

    – Russ Suter
    4 hours ago












  • @RussSuter Understood re: external forces. I was just pointing out some pitfalls that might not have been known when that decision was made. Either way, I'm unable to find my notes or reproduce the scenario from the few details I remember of it. I just remember something definitely changing in 2017 with regards to transactions and calling code from an assembly, and being really annoyed with it as it seemed like a needless change for the worse, and I had to work around it for what I was testing that worked fine in prior versions. So, please post a link in the question to the deadlock XML.

    – Solomon Rutzky
    3 hours ago











  • Thanks for that additional info. Here's a link to the XML: dropbox.com/s/n9w8nsdojqdypqm/deadlock17.xml?dl=0

    – Russ Suter
    2 hours ago











  • @RussSuter Have you tried this with inlining the T-SQL? Looking at the deadlock XML (which is not easy as it's a single line--all newlines got removed somehow) it appears to be a series of PAGE locks between sessions 60 and 78. There are 8 pages locked between both sessions: 3 for one SPID and 5 for the other. Each with a different process ID, so this is an issue of parallelism. If this is related to SQLCLR, it might ironically be the fact that SQLCLR isn't preventing parallelism. This is why I asked if you have tried putting the simple function inline as that might also show the deadlock.

    – Solomon Rutzky
    1 hour ago













4












4








4







What version(s) of SQL Server are you using?



I do recall seeing a slight change in behavior in SQL Server 2017 not too long ago. I will have to go back and see if I can find where I made a note of it, but I think it had to do with a schema lock being initiated when a SQLCLR object was being accessed.



While I am looking for that, I will say the following regarding your approach:



  1. Please use the Sql* types for input parameters, return types. You should be using SqlString instead of string. SqlString is very similar to a nullable string (your value?, but it has other functionality built in that is SQL Server-specific. All of the Sql* types have a Value property that returns the expected .NET type (e.g. SqlString.Value returns string, SqlInt32 returns int, SqlDateTime returns DateTime, etc).


  2. I would recommend against this entire approach to begin with, whether or not the deadlocks are related. I say this because:



    1. Even with deterministic SQLCLR UDFs being able to participate in parallel plans, you are most likely going to get performance hits for emulating simplistic built-in functions.

    2. The SQLCLR API does not allow for VARCHAR. Are you ok with implicitly converting everything to NVARCHAR and then again back to VARCHAR for simple operations?

    3. The SQLCLR API does not allow for overloading, so you might need multiple versions of functions that do allow for different signatures in T-SQL and/or PL/SQL.

    4. Similar to not allowing for overloading, there is a big difference between NVARCHAR(4000) and NVARCHAR(MAX): the MAX type (having even a single one of them in the signature) make the SQLCLR call take twice as long as not having any MAX type in the signature (I believe this holds true for VARBINARY(MAX) vs VARBINARY(4000) as well). So, you need to decide between:

      • using only NVARCHAR(MAX) to have a simplified API, but take the performance hit when you are using 8000 bytes or less of string data, or

      • creating two variations for all / most / many string functions: one with MAX types, and one without (for when you are guaranteed to never go over 8000 bytes of string data in or out). This is the approach I chose to take for most of the functions in my SQL# library: there is a Trim() function which likely has one or more MAX types, and a Trim4k() version which never has a MAX type anywhere in the signature or result set schema. The "4k" versions are absolutely more efficient.



    5. You are not being careful to emulate functionality given the example in the question. LTRIM and RTRIM only trim spaces, while .NET String.Trim() trims white space (at least space, tabs, and newlines). For example:



       PRINT LTRIM(RTRIM(N' a '));


    6. Also, I just noticed that your function, both in T-SQL and in C#, only uses 1 of the 3 input parameters. Is this just a proof of concept, or redacted code?






share|improve this answer















What version(s) of SQL Server are you using?



I do recall seeing a slight change in behavior in SQL Server 2017 not too long ago. I will have to go back and see if I can find where I made a note of it, but I think it had to do with a schema lock being initiated when a SQLCLR object was being accessed.



While I am looking for that, I will say the following regarding your approach:



  1. Please use the Sql* types for input parameters, return types. You should be using SqlString instead of string. SqlString is very similar to a nullable string (your value?, but it has other functionality built in that is SQL Server-specific. All of the Sql* types have a Value property that returns the expected .NET type (e.g. SqlString.Value returns string, SqlInt32 returns int, SqlDateTime returns DateTime, etc).


  2. I would recommend against this entire approach to begin with, whether or not the deadlocks are related. I say this because:



    1. Even with deterministic SQLCLR UDFs being able to participate in parallel plans, you are most likely going to get performance hits for emulating simplistic built-in functions.

    2. The SQLCLR API does not allow for VARCHAR. Are you ok with implicitly converting everything to NVARCHAR and then again back to VARCHAR for simple operations?

    3. The SQLCLR API does not allow for overloading, so you might need multiple versions of functions that do allow for different signatures in T-SQL and/or PL/SQL.

    4. Similar to not allowing for overloading, there is a big difference between NVARCHAR(4000) and NVARCHAR(MAX): the MAX type (having even a single one of them in the signature) make the SQLCLR call take twice as long as not having any MAX type in the signature (I believe this holds true for VARBINARY(MAX) vs VARBINARY(4000) as well). So, you need to decide between:

      • using only NVARCHAR(MAX) to have a simplified API, but take the performance hit when you are using 8000 bytes or less of string data, or

      • creating two variations for all / most / many string functions: one with MAX types, and one without (for when you are guaranteed to never go over 8000 bytes of string data in or out). This is the approach I chose to take for most of the functions in my SQL# library: there is a Trim() function which likely has one or more MAX types, and a Trim4k() version which never has a MAX type anywhere in the signature or result set schema. The "4k" versions are absolutely more efficient.



    5. You are not being careful to emulate functionality given the example in the question. LTRIM and RTRIM only trim spaces, while .NET String.Trim() trims white space (at least space, tabs, and newlines). For example:



       PRINT LTRIM(RTRIM(N' a '));


    6. Also, I just noticed that your function, both in T-SQL and in C#, only uses 1 of the 3 input parameters. Is this just a proof of concept, or redacted code?







share|improve this answer














share|improve this answer



share|improve this answer








edited 4 hours ago

























answered 4 hours ago









Solomon RutzkySolomon Rutzky

49.9k585184




49.9k585184












  • 1. Thanks for the tip on using the Sql types. I'll make that change now. 2. There are external forces at work here which necessitate the use of them. I'm not thrilled about it but trust me, it's better than the alternative. My original question contains a little bit of the explanation as to why a seemingly asinine function exists and is being used.

    – Russ Suter
    4 hours ago












  • @RussSuter Understood re: external forces. I was just pointing out some pitfalls that might not have been known when that decision was made. Either way, I'm unable to find my notes or reproduce the scenario from the few details I remember of it. I just remember something definitely changing in 2017 with regards to transactions and calling code from an assembly, and being really annoyed with it as it seemed like a needless change for the worse, and I had to work around it for what I was testing that worked fine in prior versions. So, please post a link in the question to the deadlock XML.

    – Solomon Rutzky
    3 hours ago











  • Thanks for that additional info. Here's a link to the XML: dropbox.com/s/n9w8nsdojqdypqm/deadlock17.xml?dl=0

    – Russ Suter
    2 hours ago











  • @RussSuter Have you tried this with inlining the T-SQL? Looking at the deadlock XML (which is not easy as it's a single line--all newlines got removed somehow) it appears to be a series of PAGE locks between sessions 60 and 78. There are 8 pages locked between both sessions: 3 for one SPID and 5 for the other. Each with a different process ID, so this is an issue of parallelism. If this is related to SQLCLR, it might ironically be the fact that SQLCLR isn't preventing parallelism. This is why I asked if you have tried putting the simple function inline as that might also show the deadlock.

    – Solomon Rutzky
    1 hour ago

















  • 1. Thanks for the tip on using the Sql types. I'll make that change now. 2. There are external forces at work here which necessitate the use of them. I'm not thrilled about it but trust me, it's better than the alternative. My original question contains a little bit of the explanation as to why a seemingly asinine function exists and is being used.

    – Russ Suter
    4 hours ago












  • @RussSuter Understood re: external forces. I was just pointing out some pitfalls that might not have been known when that decision was made. Either way, I'm unable to find my notes or reproduce the scenario from the few details I remember of it. I just remember something definitely changing in 2017 with regards to transactions and calling code from an assembly, and being really annoyed with it as it seemed like a needless change for the worse, and I had to work around it for what I was testing that worked fine in prior versions. So, please post a link in the question to the deadlock XML.

    – Solomon Rutzky
    3 hours ago











  • Thanks for that additional info. Here's a link to the XML: dropbox.com/s/n9w8nsdojqdypqm/deadlock17.xml?dl=0

    – Russ Suter
    2 hours ago











  • @RussSuter Have you tried this with inlining the T-SQL? Looking at the deadlock XML (which is not easy as it's a single line--all newlines got removed somehow) it appears to be a series of PAGE locks between sessions 60 and 78. There are 8 pages locked between both sessions: 3 for one SPID and 5 for the other. Each with a different process ID, so this is an issue of parallelism. If this is related to SQLCLR, it might ironically be the fact that SQLCLR isn't preventing parallelism. This is why I asked if you have tried putting the simple function inline as that might also show the deadlock.

    – Solomon Rutzky
    1 hour ago
















1. Thanks for the tip on using the Sql types. I'll make that change now. 2. There are external forces at work here which necessitate the use of them. I'm not thrilled about it but trust me, it's better than the alternative. My original question contains a little bit of the explanation as to why a seemingly asinine function exists and is being used.

– Russ Suter
4 hours ago






1. Thanks for the tip on using the Sql types. I'll make that change now. 2. There are external forces at work here which necessitate the use of them. I'm not thrilled about it but trust me, it's better than the alternative. My original question contains a little bit of the explanation as to why a seemingly asinine function exists and is being used.

– Russ Suter
4 hours ago














@RussSuter Understood re: external forces. I was just pointing out some pitfalls that might not have been known when that decision was made. Either way, I'm unable to find my notes or reproduce the scenario from the few details I remember of it. I just remember something definitely changing in 2017 with regards to transactions and calling code from an assembly, and being really annoyed with it as it seemed like a needless change for the worse, and I had to work around it for what I was testing that worked fine in prior versions. So, please post a link in the question to the deadlock XML.

– Solomon Rutzky
3 hours ago





@RussSuter Understood re: external forces. I was just pointing out some pitfalls that might not have been known when that decision was made. Either way, I'm unable to find my notes or reproduce the scenario from the few details I remember of it. I just remember something definitely changing in 2017 with regards to transactions and calling code from an assembly, and being really annoyed with it as it seemed like a needless change for the worse, and I had to work around it for what I was testing that worked fine in prior versions. So, please post a link in the question to the deadlock XML.

– Solomon Rutzky
3 hours ago













Thanks for that additional info. Here's a link to the XML: dropbox.com/s/n9w8nsdojqdypqm/deadlock17.xml?dl=0

– Russ Suter
2 hours ago





Thanks for that additional info. Here's a link to the XML: dropbox.com/s/n9w8nsdojqdypqm/deadlock17.xml?dl=0

– Russ Suter
2 hours ago













@RussSuter Have you tried this with inlining the T-SQL? Looking at the deadlock XML (which is not easy as it's a single line--all newlines got removed somehow) it appears to be a series of PAGE locks between sessions 60 and 78. There are 8 pages locked between both sessions: 3 for one SPID and 5 for the other. Each with a different process ID, so this is an issue of parallelism. If this is related to SQLCLR, it might ironically be the fact that SQLCLR isn't preventing parallelism. This is why I asked if you have tried putting the simple function inline as that might also show the deadlock.

– Solomon Rutzky
1 hour ago





@RussSuter Have you tried this with inlining the T-SQL? Looking at the deadlock XML (which is not easy as it's a single line--all newlines got removed somehow) it appears to be a series of PAGE locks between sessions 60 and 78. There are 8 pages locked between both sessions: 3 for one SPID and 5 for the other. Each with a different process ID, so this is an issue of parallelism. If this is related to SQLCLR, it might ironically be the fact that SQLCLR isn't preventing parallelism. This is why I asked if you have tried putting the simple function inline as that might also show the deadlock.

– Solomon Rutzky
1 hour ago










Russ Suter is a new contributor. Be nice, and check out our Code of Conduct.









draft saved

draft discarded


















Russ Suter is a new contributor. Be nice, and check out our Code of Conduct.












Russ Suter is a new contributor. Be nice, and check out our Code of Conduct.











Russ Suter is a new contributor. Be nice, and check out our Code of Conduct.














Thanks for contributing an answer to Database Administrators Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f236794%2fapparently-my-clr-assembly-function-is-causing-deadlocks%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Era Viking Índice Início da Era Viquingue | Cotidiano | Sociedade | Língua | Religião | A arte | As primeiras cidades | As viagens dos viquingues | Viquingues do Oeste e Leste | Fim da Era Viquingue | Fontes históricas | Referências Bibliografia | Ligações externas | Menu de navegação«Sverige då!»«Handel I vikingetid»«O que é Nórdico Antigo»Mito, magia e religião na volsunga saga Um olhar sobre a trajetória mítica do herói sigurd«Bonden var den verklige vikingen»«Vikingatiden»«Vikingatiden»«Vinland»«Guerreiras de Óðinn: As Valkyrjor na Mitologia Viking»1519-9053«Esculpindo símbolos e seres: A arte viking em pedras rúnicas»1679-9313Historia - Tema: VikingarnaAventura e Magia no Mundo das Sagas IslandesasEra Vikinge

What's the metal clinking sound at the end of credits in Avengers: Endgame?What makes Thanos so strong in Avengers: Endgame?Who is the character that appears at the end of Endgame?What happens to Mjolnir (Thor's hammer) at the end of Endgame?The People's Ages in Avengers: EndgameWhat did Nebula do in Avengers: Endgame?Messing with time in the Avengers: Endgame climaxAvengers: Endgame timelineWhat are the time-travel rules in Avengers Endgame?Why use this song in Avengers: Endgame Opening Logo Sequence?Peggy's age in Avengers Endgame

Are there legal definitions of ethnicities/races? The 2019 Stack Overflow Developer Survey Results Are In Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)Legal definitions in the United StatesAre there truly legal limits on US interest rates?Are gender identity and sexual orientation federally protected?Why is there an apparent legal bias against digital services?What limits are there to the powers of individual judges in the United States legal system?Are women only scholarships legal under Irish / EU law?Is the term “race” defined by Public Law enacted by Congress of the United StatesIs there a legal definition of race in the US?Neighbors are spying for landlord on Renters is it legal?Are Protected Classes Bi-directional?