I have an UPDATE command that is failing due to a timeout on SQL Server. It's a large table used for storing events, and the primary key is a NON-clustered index (shouldn't really matter anyway as it's a uniqueidentifier column).
It's updating a single row: update [table] set [field] = 1 where [primary_key] = [primary_key_value];. The problem is likely to be that there are over 200,000,000 rows so it takes a long time to find each one.
In terms of SQL Server's preference, am I better off increasing the command timeout (yes, I know the default of 30 seconds is already 30 times longer than any reasonable query should take), or should I introduce maybe a shorter timeout, but retry over and over again (to a limit)?
So is one long 60 second command timeout better than 6 retries with 5 second timeouts?
In practice there'd be some sort of exponential backoff and circuit breaker implementation, of course.
This is a bit long for a comment.
Retrying is only going to help if the reason for the timeout is due to resource contention. In that case, you are probably better off with some sort of exponential backoff, rather than just running the queries immediately.
However, I would speculate that the reason is due to either:
An unoptimized query.
A large number of rows being updated.
If the number of rows is the issue, you can limit the update to, say, 100 rows and repeat the update until all are completed. However, I would first investigate the query to see if it can be can be optimized in other ways.
Related
I'm trying to query the PostgreSQL database, but this is a public server and I really don't want to waste a lot of CPU for a long time.
So I wonder if there is some way to limit my query time for a specific duration, for example, 3/5/10 minutes.
I assume that there is syntax like limit but not for results amount but for query duration.
Thanks for any kind of help.
Set statement_timeout, then your query will be terminated with an error if it exceeds that limit.
According to this documentation:
statement_timeout (integer)
Abort any statement that takes more than
the specified number of milliseconds, starting from the time the
command arrives at the server from the client. If
log_min_error_statement is set to ERROR or lower, the statement that
timed out will also be logged. A value of zero (the default) turns
this off.
Setting statement_timeout in postgresql.conf is not recommended
because it would affect all sessions.
Here is a potential catch with using LIMIT to control how long a query might run. Rightfully, you ought to also be using ORDER BY with your query, to tell Postgres how exactly it should limit the size of the result set. But the caveat here is that Postgres would typically have to materialize the entire result set when using LIMIT with ORDER BY, and then also possibly sort, which might take longer than just reading in the entire result set.
One workaround to this might be to just use LIMIT without ORDER BY. If the execution plan does not include reading the entire table and sorting, it might be one way to do what you want. However, keep in mind that if you go this route, Postgres would have free license to return any records from the table it wishes, in any order. This is probably not what you want from a business or reporting point of view.
But, a much better approach here would be just tune your query using things like indices, and make it faster to the point where you don't need to resort to a LIMIT trick.
I'm trying to update a modest dataset of 60k records with a value which takes a little time to compute. From a small trial run of 6k records in the production environment, it took 4 minutes to complete, so the full execution should take around 40 minutes.
However this trial run showed that there were SQL timeouts occurring on user requests when accessing data in related tables (but not necessarily on the actual rows which were being updated).
My question is, is there a way of running non-urgent queries as a background operation in the SQL server without causing timeouts or table locking for extensive periods of time? The data within the column which is being updated during this period is not essential to have the new value returned; aka if a request happened to come in for this row, returning the old value would be perfectly acceptable rather than locking the set until the update is complete (I'm not sure the ins and outs of how this works, obviously I do want to prevent data corruption; could be a way of queuing any additional changes in the background)
This is possibly a situation where the NOLOCK hint is appropriate. You can read about SQL Server isolation levels in the documentation. And Googling "SQL Server NOLOCK" will give you plenty of material on why you should not over-use the construct.
I might also investigate whether you need a SQL query to compute values. A single query that takes 4 minutes on 6k records . . . well, that is a long time. You might want to consider reading the data into an application (say, using Python, R, or whatever) and doing the data manipulation there. It may also be possible to speed up the query processing itself.
I hope someone can help me. I have a simple sql statement
delete from sometable
where tableidcolumn in (...)
I have 500 records I want to delete and recreate. The table recently grew to over 1 mill records. The problem is the statement above is taking over 5 minutes without completing. I have a primary key and 2 non clustered non unique indexes. My delete statement is using the primary key.
Can anyone help me understand why this statement is taking so long and how I can speed it up?
There are two areas I would look at first, locking and a bad plan.
Locking - run your query and while it is running see if it is being blocked by anything else "select * from sys.dm_exec_requests where blocking_session_id <> 0" if you see anything blocking your request then I would start with looking at:
https://www.simple-talk.com/sql/database-administration/the-dba-as-detective-troubleshooting-locking-and-blocking/
If there is no locking then get the execution plan for the insert, what is it doing? it it exceptionally high?
Other than that, how long do you expect it to take? Is it a little bit longer than that or a lot longer? Did it only get so slow after it grew significantly or has it been getting slower over a long period of time?
What is the I/O performance, what are your average read / write times etc etc.
TL;DR: Don't do that (instead of a big 'in' clause: preload and use a temporary table).
With the number of parameters, unknown backend configuration (even though it should be fine by today's standards) and not able to guess what your in-memory size may be during processing, you may be hitting (in order) a stack, batch or memory size limit, starting with this answer. Also possible to hit an instruction size limit.
The troubleshooting comments may lead you to another answer. My pivot's the 'in' clause, statement size, and that all of these links include advice to preload a temporary table and use that with your query.
I have a client app that is submitting the following command to SQL Server 2005. At a specific time of day we are having performance issues where some of the requests are taking between 2 - 8 seconds to run when the norm is below 300ms. We are researching SQL Server options as well as all external variables that can impact the server.
My question here is how/why can a request take 8 seconds and during this time many other identical requests start and finish during this 8 second window? What can be preventing the 8 second call from finishing, but not prevent or slow down the other calls?
Running server profiler during this time the number of reads are around 20 and the writes less than 5 for all (long and short durations) the calls.
The table being inserted into has around 22M records. We are keeping about 30 days worth of data. We will probably change the approach to archive this data daily and keep the daily insert table small and index free, but really want to understand what is happening here.
There are no triggers on this table.
There are 3 indexes for GUID, Time and WebServerName (none are clustered)
Here's the command being submitted:
exec sp_executesql N'Insert Into WebSvcLog_Duration (guid,time,webservername,systemidentity,useridentity,metricname,details,duration,eventtype)values(#guid,#time,#webservername,#systemidentity,#useridentity,#metricname,#details,#duration,#eventtype)',N'#guid nvarchar(36),#time datetime,#webservername nvarchar(10),#systemidentity nvarchar(10),#useridentity nvarchar(8),#metricname nvarchar(5),#details nvarchar(101),#duration float,#eventtype int',#guid=N'...',#time='...',#webservername=N'...',#systemidentity=N'...',#useridentity=N'...',#metricname=N'...',#details=N'...',#duration=0.0,#eventtype=1
The probable reason why is heap fragmentation; you didn't mention if you had some sort of index maintenance going on, so I'm assuming that it's non-existent. The best way to minimize fragmentation is to build a clustered index on a monotonic value (a column with a naturally increasing order). I'm not sure what the time column is supposed to represent, but if it's the time of insertion, then it might be a good candidate for a clustered index; if not, then I'd add a column that captures the time inserted into the table and build a clustered index on that.
I have a single process that queries a table for records where PROCESS_IND = 'N', does some processing, and then updates the PROCESS_IND to 'Y'.
I'd like to allow for multiple instances of this process to run, but don't know what the best practices are for avoiding concurrency problems.
Where should I start?
The pattern I'd use is as follows:
Create columns "lockedby" and "locktime" which are a thread/process/machine ID and timestamp respectively (you'll need the machine ID when you split the processing between several machines)
Each task would do a query such as:
UPDATE taskstable SET lockedby=(my id), locktime=now() WHERE lockedby IS NULL ORDER BY ID LIMIT 10
Where 10 is the "batch size".
Then each task does a SELECT to find out which rows it has "locked" for processing, and processes those
After each row is complete, you set lockedby and locktime back to NULL
All this is done in a loop for as many batches as exist.
A cron job or scheduled task, periodically resets the "lockedby" of any row whose locktime is too long ago, as they were presumably done by a task which has hung or crashed. Someone else will then pick them up
The LIMIT 10 is MySQL specific but other databases have equivalents. The ORDER BY is import to avoid the query being nondeterministic.
Although I understand the intention I would disagree on going to row level locking immediately. This will reduce your response time and may actually make your situation worse. If after testing you are seeing concurrency issues with APL you should do an iterative move to “datapage” locking first!
To really answer this question properly more information would be required about the table structure and the indexes involved, but to explain further.
DOL, datarow locking uses a lot more locks than allpage/page level locking. The overhead in managing all the locks and hence the decrease of available memory due to requests for more lock structures within the cache will decrease performance and counter any gains you may have by moving to a more concurrent approach.
Test your approach without the move first on APL (all page locking ‘default’) then if issues are seen move to DOL (datapage first then datarow). Keep in mind when you switch a table to DOL all responses on that table become slightly worse, the table uses more space and the table becomes more prone to fragmentation which requires regular maintenance.
So in short don’t move to datarows straight off try your concurrency approach first then if there are issues use datapage locking first then last resort datarows.
You should enable row level locking on the table with:
CREATE TABLE mytable (...) LOCK DATAROWS
Then you:
Begin the transaction
Select your row with FOR UPDATE option (which will lock it)
Do whatever you want.
No other process can do anything to this row until the transaction ends.
P. S. Some mention overhead problems that can result from using LOCK DATAROWS.
Yes, there is overhead, though i'd hardly call it a problem for a table like this.
But if you switch to DATAPAGES then you may lock only one row per PAGE (2k by default), and processes whose rows reside in one page will not be able to run concurrently.
If we are talking of table with dozen of rows being locked at once, there hardly will be any noticeable performance drop.
Process concurrency is of much more importance for design like that.
The most obvious way is locking, if your database doesn't have locks, you could implement it yourself by adding a "Locked" field.
Some of the ways to simplify the concurrency is to randomize the access to unprocessed items, so instead of competition on the first item, they distribute the access randomly.
Convert the procedure to a single SQL statement and process multiple rows as a single batch. This is how databases are supposed to work.