问题
If SQL is used directly or created by NHibernate, with possibly big "where in / not in ([1 to 100 parameters])" conditions, does it make sense to fill up parameters to certain limits, to have a limited number of query plans?
Parameters are int/number, DBMS is MSSQL or Oracle. The queries are called via sp_executesql/executeimmediate to enforce query plan caching.
Normally, such a query would have up to 100 query plans for the same query. Several such queries might quickly fill up the cache, or result in poor performance by not using cached query plans at all.
A user may fill up the parameter list by repeating the last value, until a certain number of parameters is reached?
As far as I know, MSSQL and Oracle identify known queries by string equality, resulting in a different query plan for each different number of parameters.
(values would of course be parameters and not concatenated numbers).
SELECT * FROM MyTable WHERE Id in (4001, 4002, 4003, ... , 4055, 4056)
with 56 parameters, change to:
SELECT * FROM MyTable WHERE Id in (4001, 4002, 4003, ... , 4055, 4056, 4056, 4056, 4056, 4056)
having 60 parameters by repeating value 4056, with all long "in" lists having lengths of 50, 60, 70, 80, 90, 100. Only less than 10 params will be left.
For such a query with up to 100 parameters, there would be 10 query plans for 10 to 100 parameters, plus 9 query plans for 1 to 9 parameters (no fill).
EDIT: I found that NHibernate (3.1.0.4 or later) and SQL Server, with batch-size="200" actually splits parameter lists into multiple statements, with fixed length param lists. For example, select with 118 ID parameters and batch-size="200" may be sent as three selects with 100, 12 and 6 IDs, instead of one with 118 IDs. This is similar to what I wanted, batch-size="200" not with 200 different SQL strings and thus query plans accumulating over time, but only a smaller number, perhaps 16. There seemed to be one SQL for each parameter count between 1 and 12, then statements with 25, 50 and 100 parameters. Maybe filling up with a repeated value -can- be more efficient, but this is a good way to ensure query plan reuse.
回答1:
If you have a large number of query parameters that all represent the same value type, they should be a column in a table, not a parameter list.
If they are sufficiently static, put them in a filter table and do:
SELECT t.*
FROM MyTable t
INNER JOIN FilterTable f ON t.Id = f.Id
If they are completely dynamic, then use a Table Valued Parameter. In SQL Server 2008 I am able to pass table-valued parameter to my stored procedure from NHibernate.How to achieve the same in Oracle
来源:https://stackoverflow.com/questions/17620105/parameterized-sql-in-not-in-with-fixed-numbers-of-parameters-for-query-plan