-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SqlServer AdoJobStore SqlParameter without text size generates pressure on server #939
Comments
Very interesting find and thank you for the detailed breakdown. Would you be interested to submit a PR to fix this? |
Sure, let me know if you have some hints or precautions. I fork it for submit asap a PR with the fix. |
Quick check makes me believe that it's just like you said, adding size info to invoked
Becomes:
Hopefully we don't run to issues between databases, the sizes should be same for every schema and provider code quite the same. |
I agree with you this is a simple solution and in the same place where the code is more binded to the schema so the first place to check in case of future schema changes. This change is supported by others engine and the sizes are the same across the different engines. Other options like read schema metadata to get the column size are too complex just for that. I will test that fix also in a real production environment where now is clearly an isssue and check the result. |
One option could also infer some default like size 4000 when it's the case of string going in. Size would be fixed and always the same? Even though bigger than the actual database size but I guess that doesn't matter? |
There are different sizes for each column so a better approach is to set a default value like that or nvarchar(max).
|
I see there's now the 4000? It could be easy too hook into here: quartznet/src/Quartz/Impl/AdoJobStore/StdAdoDelegate.cs Lines 3357 to 3365 in effbc3e
As SQL Server already does to detect binary: quartznet/src/Quartz/Impl/AdoJobStore/SqlServerDelegate.cs Lines 62 to 82 in effbc3e
So it would be enough do something like |
I was reminded that NHibernate sets 4000 for nvarchar and 8000 for varchar when none supplied, haven't double-checked. |
i'm testing if has sense a default value inside AdoUtil.AddCommandParameter for every type because it seems size is used only for variable sized types like varchar, vcarchar, varbinary and -1 is max value. param.Size = size ?? -1; otherwise after the param creation, the param.DbType has the real type and we can fix it only for a string type where size is not specified. otherwise if we want to be more strict and fix it just for now in the SqlServer part we can extend the part in SqlServerDelegate for datatype null, size null and check if it works well with integer and others or check the object value type for a string type to restrict the fix (because dataType is never specified unless varbinary). i'm not sure about performance on setting a default value (never specified in the real queries) with a max value, maybe is a memory evluation overkill i don't know the impact but i can test it. |
I think
would be quite safe? Data type is only set explicitly for binary if I remember rights. This could also go just to SqlServerDelegate, I'm unsure how query plans work with other DBs, do they suffer from this problem. |
This fix in SqlServerDelegate is perfect to have a first feedback and think about the issue on other DBs in a second time. |
|
I tested NHibernate 5.1.2 version, it set a fixed default value of 4000 for nvarchar when querying a mapped column with [StringLength(50)] and the same size on database column |
Great investigation, thank you for this. Out of curiosity, how big is your deployment? Trigger/job/node count-wise. I bet it requires some load to surface this. |
tens of processes, 10 schedulers, a few hundreds of jobs with single simple triggers running clustered on a single dedicated database for quartz. Probably it is too chatty on the server also after the fix on the plan cache. |
The AdoJobStore implementation was recently fixed for the sched_name parameter in 3.1.0 but is still having pressure on Sql Server plan cache due to the missing SqlParameter size property for text parameters.
This generates a lot of distinct sql plans. Here some plans generated, this is the 3.0.0 version without the fix on scheduler name parameter but the issue still remains in latest:
(@triggerRepeatCount int,@triggerRepeatInterval bigint,@triggerTimesTriggered int,@triggerName nvarchar(12),@triggerGroup nvarchar(17))UPDATE QRTZ_SIMPLE_TRIGGERS SET REPEAT_COUNT = @triggerRepeatCount, REPEAT_INTERVAL = @triggerRepeatInterval, TIMES_TRIGGERED = @triggerTimesTriggered WHERE SCHED_NAME = 'scheduler' AND TRIGGER_NAME = @triggerName AND TRIGGER_GROUP = @triggerGroup
(@triggerRepeatCount int,@triggerRepeatInterval bigint,@triggerTimesTriggered int,@triggerName nvarchar(10),@triggerGroup nvarchar(10))UPDATE QRTZ_SIMPLE_TRIGGERS SET REPEAT_COUNT = @triggerRepeatCount, REPEAT_INTERVAL = @triggerRepeatInterval, TIMES_TRIGGERED = @triggerTimesTriggered WHERE SCHED_NAME = 'scheduler' AND TRIGGER_NAME = @triggerName AND TRIGGER_GROUP = @triggerGroup
As you can see without the parameter size it take the size from the value itself generating similar plans.
To watch the plan cache generated on a SqlServer:
SELECT DISTINCT dm_exec_sql_text.text, creation_time FROM sys.dm_exec_cached_plans CROSS APPLY sys.dm_exec_query_plan(plan_handle) INNER JOIN sys.dm_exec_query_stats ON dm_exec_query_stats.plan_handle = dm_exec_cached_plans.plan_handle CROSS APPLY sys.dm_exec_sql_text(dm_exec_query_stats.plan_handle) WHERE text LIKE '%qrtz%' ORDER BY dm_exec_sql_text.text DESC;
This port to a plan flooding that has a critical impact on the entire server.
To avoid that we can gather at startup the column size from the schema and set that value during parametrization, I think in SqlServerDelegate.AddCommandParameter for example.
The text was updated successfully, but these errors were encountered: