Getting kicked out of single user mode in SQL Server database. Why? - sql

Our application has in-built functionality to update the database it uses (triggered when an app update is downloaded from our server.)
Usually, the update comprises of table and data conversion and then a drop of existing stored procedures and a create of all current stored procedures.
So we do the following from C#:
Create Connection
Set database to Single User Mode
Run upgrade script to upgrade tables and convert data
Run upgrade script to drop existing stored procedures and add new ones
Set database to Multi User Mode
Close connection
Step 2 -5 are done using the same connection. For some clients it occassionaly errors out in the middle of Step3 or Step 4. The log shows:
Error: Database 'MyDB' is already open and can only have one user at a time.
This is very strange because at that time we are already in Single User mode so no other user should be able to connect to the database, let alone somehow put it in Single User mode for its own connection.
We are wondering if some internal SQL Server process is taking over our Single User mode and preventing us from completing the update.
We are aware that if AUTO_UPDATE_STATISTICS_ASYNC is turned ON this may interrupt Single User Mode, but we have verified that it is turned off and it still occurred for the client.
Could a CHECKPOINT operation interrupt it? If so, what do we do about that, because that is a server-wide setting so we cannot modify it.

Related

Query to get active processes in Oracle

I am trying to see what queries are currently running in an oracle DB. However, when I try using the table v$session it gives me an error:
What's the cause of this and what would be the correct way to get the active processes that are running?
I'm looking to get the necessary information to be able to cancel a query for a given user. Let me give an example:
1) User executes query in the application. We add in a comment so we can 'track' that query:
/* Query-ID-1283849 */ select * from mytable
2) Now, if the user clicks the "Cancel" button while the query is running (let's say the query is taking a very long time to respond), we allow the user to cancel that query, given that the user will probably NOT be a sys user but a 'normal' user with read-only privileges.
How could this be done?
At the fundamental database level, you can't kill individual queries. You kill individual sessions. I'm inferring from your question that your specific use case is inside an application, not a tool like Sql Developer or Sql Plus.
Session killing can be done by users that have special database privileges to kill sessions. If you are inside an application running multiple queries in one session, killing the session will effectively kill your application and require either a) an application restart or b) gracefully programatically handling the dropped session.
If you are using an n-tier ORM framework that handles database interactions for you, you may be in a position where killing the session won't have any affect on your application other than the currently running statement.
Another way in your app to handle isolating sessions and queries is to run a multi-threaded application. Each query spawns a new thread, and the thread can be killed without necessarily killing the session.
Basically, the short answer is you can kill a query only by killing its session. Your approach of looking at v$session is correct and necessary to find the session id for any givel sql statement, you just need to have your DBA grant your privileges to the v$session and v$sql synonyms.
Update specific to Sql Developer, based on OP's comment for clarification:
Sql Developer has an option to allow running parallel queries, taking advantage of threads and multiple connections. That setting is found at Tools > Preferences > Database > Worksheet. Regardless of the setting, when you click the query cancel button, the app is still sending a session kill request. The GUI will usually gracefully start a new session and the end user is none the wiser about it. But sometimes things don't work out and the GUI freezes or you end up with no connection and have to manually reconnect.
To add to the complexity, the behavior depends on the driver/client used by your application. OCI, thick clients, and thin clients have shown different behaviors in the past when it comes to kill requests. In fact, in Sql Developer, you have an option to force it to use OCI or a thick driver so that you can avoid certain behaviors.
I'd highly recommend getting rights to view v$session and play around with this. It's fun to learn more about how Oracle manages sessions.
I just discovered that the latest version, Oracle 18c, allows killing an individual query within a session. I'm on 12c so I have not tried this. https://docs.oracle.com/en/database/oracle/oracle-database/18/admin/managing-processes.html#GUID-7D8E5E00-515D-4338-8B86-C2044F6D2957
Relevant parts from the documentation.
5.10.5 Cancelling a SQL Statement in a Session You can cancel a SQL statement in a session using the ALTER SYSTEM CANCEL SQL statement.
Instead of terminating a session, you can cancel a high-load SQL
statement in a session. When you cancel a DML statement, the statement
is rolled back.
The following clauses are required in an ALTER SYSTEM CANCEL SQL
statement:
SID – Session ID
SERIAL – Session serial number
The following clauses are optional in an ALTER SYSTEM CANCEL SQL
statement:
INST_ID – Instance ID
SQL_ID – SQL ID of the SQL statement
You can view this information for a session by querying the GV$SESSION
view.
The following is the syntax for cancelling a SQL statement:
ALTER SYSTEM CANCEL SQL 'SID, SERIAL, #INST_ID, SQL_ID';

SQL Azure Database Copy status

Copying a database in the Azure Portal is never ending.
Usually, when I copy a 250GB database, it completes in just under an hour.
Today, when I copy, it never seems to finish, it has been over two to three hours now.
And in the server activity logs, the last entry just says an update occured
Any idea on how to see more progress, percent complete, or any other way to see what might be locking it? Nothing of use can be seen in the activty log json.
You can use SYS.DM_OPERATION_STATUS to track many operations including copy in SQLAZURE..
Documentation states
To use this view, you must be connected to the master database. Use the sys.dm_operation_status view in the master database of the SQL Database server to track the status of the following operations performed on a SQL Database:
Below are the operattions that can be tracked
Create database
Copy database. Database Copy creates a record in this view on both the source and target servers.
Alter database
Change the performance level of a service tier
Change the service tier of a database, such as changing from Basic to Standard.
Setting up a Geo-Replication relationship
Terminating a Geo-Replication relationship
Restore database
Delete database
You can also try sys.dm_database_copies in master database for info about copy status ..This has percent_complete field and below is what documentation has to say about this
The percentage of bytes that have been copied. Values range from 0 to 100. SQL Database may automatically recover from some errors, such as failover, and restart the database copy. In this case, percent_complete would restart from 0.
Note:
This view has info only during the duration of copy operation..

Making a connection in Single User Mode

So I have a third party vendor software that I have to call in an SQL Agent Job to restore my databases. So my first step is to set the database in single user mode, my second step is to call the software to start the restore. The problem is, the software takes so long to actually start the restore (its doing it all across the network) that another user can swoop in and take over the database.
Is there a way to put the DB in single user mode and then grab that connection right away? I have tried with a few "Select Getdate()" but I feel that is taking it from the system, and not the database. Do I have to select from a specific table in the database to get it to work?
Thanks
Rather than place the database in single user mode, take the database offline in the context of another database:
USE tempdb;
ALTER DATABASE DatabaseToRestore
SET OFFLINE WITH ROLLBACK IMMEDIATE;
Use the "Client Application Name" option along with the "-m" option that places SQL into single user mode.
That way only an application that matches the name given can connect and take the connection. Obviously you need to ensure that your client process that's doing the restore has a distinct name!
See here for info on the various SQL Server startup options: https://msdn.microsoft.com/en-us/library/ms190737.aspx
Also, I was under the impression you had to be an admin to connect in single user mode, which of course your normal users should not be. Please someone correct me if I'm wrong on that point!

Make SQL Server database read only except for one stored procedure

I have a stored procedure which migrate data from this database to another. To exclude any error, I want to make the database read only for every transaction except mine. I use SqlConnection and SqlCommand to run the script. Is there any way to do this?
Set the database to Single-user Mode. When you put it in Single-user mode, then you have the only connection available. As long as you don't relinquish your connection, no one else can connect.
Be warned, this will close all existing connections by other users. But it will prevent other connections from being made.
More information: https://msdn.microsoft.com/en-us/library/ms345598.aspx

Database based audit log for web application needs user id

I have a web application which currently only supports PostgreSQL as a backend and has it's own user management. Connection to the database is done using a generic user account using Postgres auth mechanisms. This application should now get a audit log for some created and changed data hopefully based on triggers and stored procedures only and for performance reasons it would be nice if everything works async and independent from the web application.
There is one main problem: We want to know which user of the web application made some changes or created data, but this piece of information is normally not available in stored procedures out of the box because we connect to Postgres using a generic account. What I would like to avoid doing is calling the stored procedures in the web application and provide user ids that way, as this would mean to add the relevant calls in may places in the web application. Besides that we make updates to the data model directly using the database without the web application, meaning we would need the triggers in any case.
Currently the web application is working with a transaction started on every request and committed on its end. Therefore I though of creating a temporary table within the transaction in every request which always gets the current user id of the request which should be available for the stored procedures executed by the triggers on created or changed data.
Some things I don't know are if the stored procedures executed can even access the current transaction of the database and therefore are able to retrieve the current user id from the temporary table? The table is not part of the changed data the trigger was created for. How would performance be affected if each request creates a temporary table to store just one Integer in the worst case? If the trigger is able to access the temporary table, the request may finish at any time because it's work is done or of errors. How would that affect a trigger which would have access to the temporary table which only exits within the transaction which gets committed or reverted as the stored procedures want to read the user id?
Is there any other way with which I can map a user id to some unique identifier of a transaction which the trigger has access to? Besides a temporary table, I could create a normal table in which I map user ids to transaction ids on start of every request but independent of the current transaction. If the trigger would now get the transaction id which was responsible for executing the trigger the stored procedures could use the transaction id to look up the user id which used the transaction.
Any thoughts? Thanks!
I've added a question about trigger lifetime and execution context which fits to this question:
execution context of database trigger in PostgreSQL
A temporary table seems overkill when you could just use a session setting.
Up to version 9.1, custom session variables needed to be declared in postgresql.conf through the
custom_variable_classes parameter, which made it a bit cumbersome, deployment-wise.
Since 9.2, it's no longer necessary. So you could just issue at connect time:
SET myapp.myusername='foobar';
and then in a trigger or in fact anywhere within the session, SELECT current_setting('myapp.myusername'), or SHOW myapp.myusername would get back the value.