Database from AlwaysOn availability group restored as normal database

1

I have a problem with a normal SQL database restored from a DB set in AlwaysOn high availability group in SQL Server 2017.

I restored a copy of production db to a different server, to be used as QA test database, with a different name also - MyDB_demo

The problem is, the QA app copy (same code as production with new development enhancements) get an error at some point.

Even if my conn str points to MyDB_demo, I get the following error

[SqlException (0x80131904): The target database ('MyDB') is in an availability group and is currently accessible for connections when the application intent is set to read only. For more information about application intent, see SQL Server Books Online.]

System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action 1 wrapCloseInAction) +2444190
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action 1 wrapCloseInAction) +5775712
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) +285
System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) +4169
System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() +58
System.Data.SqlClient.SqlDataReader.get_MetaData() +89
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption) +409
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) +2127
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) +911
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +64
System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +240
System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) +41
System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior) +12
System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior) +139
System.Data.Common.DbDataAdapter.Fill(DataSet dataSet, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior) +136
System.Data.Common.DbDataAdapter.Fill(DataSet dataSet) +88
MyApp.SqlHelper.ExecuteDataset(SqlConnection connection, CommandType commandType, String commandText, SqlParameter[] commandParameters) +163
MyApp.PermitFunctions.GetSystemMessages(String sp, Int32 iPermitID, Int32 iAppID, SqlConnection cn) +219
MyApp.Municipality.LoadSystemMessage() +3869
MyApp.Municipality.Page_Load(Object sender, EventArgs e) +101
System.Web.UI.Control.OnLoad(EventArgs e) +95
System.Web.UI.Control.LoadRecursive() +59
System.Web.UI.Control.LoadRecursive() +131
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +678

Is there any reference in the newly restored DB (named now MyDB_demo) that stores the original name of production DB and why is it trying to access it?

Any suggestion is appreciated.

EDIT

Actually, the server used to restore MyDB_demo is one of the secondary nodes for AlwasyOn availability group; it also contains a RO copy of production database, MyDB.

So the server has:

  • RO copy of production DB (MyDB)
  • normal, stand-alone db restored for QA - MyDB_demo

Hence, I understand the error message - it would makes sense if I tried to access directly the secondary, RO copy of production db from connection string.

But I do not: the connection string (which I double-checked) is trying to connect to QA db, MyDB_demo.

Here is some additional info:

  • the error is thrown in SQLHelper class, the helper class from MS to work with SQL Server, in the ExecuteDataset function
  • the error is thrown ONLY on one stored procedure - lot of other stored procedures and also direct SQL statements run just fine
  • I inspected the stored procedure, thinking it might contains accidentally a hardcoded reference to DB name - it doesn't
  • and the strange part - I run the stored procedure with the same parameters as called from the app in SSMS - and it run just fine - no error

So it looks somehow the connection string MIGHT be altered (!!!) is some way by the NET application itself, and only for this stored procedure?

Anyone ever encountered something like this?

Thank you

database-restore
sql-server-2017
alwayson
asked on Stack Overflow Jun 10, 2018 by bzamfir • edited Jun 11, 2018 by bzamfir

1 Answer

0

Due to the strange (read: stupid) situation that the culprit SP fails only when called from within app, but runs ok when tried in SSMS, I tried a "stupid" approach: I inspected its code, commented out two fields that were set with sub-selects like select top 1 from ..... where.... (actually I replaced theit values with dummy ones) and I changed an Order By field that was initially specified like "InspectionType" Desc, which I removed quotation marks from.

Doing this, the SP suddenly started to work ok even when called from the app. Then I reverted all changes to original (added quoted back and put back the sub-selects) and the SP continued to work ok.

So ... problem solved. Stupid approach for stupid problem (!?!?!)

In any case, if anyone has a better idea or explanation of what might have happened, I'd be glad to hear it


EDIT

I think I understand the fix. By editing and saving the stored procedure, its query plan was recompiled. So the original error might have been caused by the old query plan. But why did it referenced the database name? Is the actual database name referenced in query plans? This looks a little odd to me.

And another question (open):

Does the SQL Server optimizer detect if a DB runs in high-availability mode, and when optimizing the queries, does it decide if a query is read-only mode and automatically redirects it toward a read-only node? Even if the ApplicationIntent readonly parameter is not present in connection string? Because it was not in this case, even in production - we just implemented AlwaysOn functionality and are in the process of updating app to take advantage of R/O nodes.

Any comments are appreciated

answered on Stack Overflow Jun 10, 2018 by bzamfir • edited Jun 11, 2018 by bzamfir

User contributions licensed under CC BY-SA 3.0