I have a SQL CLR UDF which queries a web service. Since this can be costly, especially within the function is part of a query on multiple rows, I would like to avoid calling the web service whenever possible. In every case, the same input will yield the same output (e.g., if my input is ‘abc’ I will always get ‘xyz’ and nothing different, likewise ‘def’ will always yield ‘tuv’, etc).
I have done some tests, and it seems that SQL does not do any sort of caching on its end, so the web service will always be invoked.
Example Case: I have a table MyTable with a field MyField1. While MyTable has 500 rows, MyField1 will always only have one of 3 possible values. Example query:
SELECT MyFunction(MyField1) FROM MyTable
What happens is that the web service will be called 500 times, once for each row in the table. What I would prefer is that the web service is only called 3 times (once for each distinct value), and read from some cache for the duplicate values.
Example Code:
[SqlFunction]
public static SqlString MyFunction(SqlString input)
{
if (input.IsNull) return SqlString.Null;
using (var webService = new MyWebService())
{
string result = webService.Call(input.Value);
return new SqlString(result);
}
}
What I would really prefer is to keep this in a cache that is specific to the context. That is, the cache would only exist to cache results within the call of a single stored procedure, or within a single query window, etc. Is there any available mechanism to accomplish what I’m after?
EDIT
NOTE The updated version towards the end
Although this answer doesn’t use caching, it should minimise the number of calls to your function. using a number of
CTEsto find the distinct values of myField1, then lookup the distinct values in the webservice using your function, then join these back to MyTable. The example below probably makes it clearer:SQL Fiddle
MS SQL Server 2008 Schema Setup:
Query 1:
Results:
EDIT:
Note when I check a SQL Profiler trace of the aboce, I see a 1000 calls to the UDF, in other words the query analyser is generating a plan which expands out the CTE’s and calls the UDF once for each row.
The following uses a table variable to ensure that the UDF is only called 3 times. I have traced this in SQL Profiler and it is much more efficient. This uses the same table and functions as above. Need SQLFiddle Attached
SQL Fiddle
MS SQL Server 2008 Schema Setup:
Query 1:
Results: