SQL Server : subscription : how to know if a table is under replication/subscription - sql

In SQL Server, on the "Subscription side", how can you know if a table is under replication/subscription?
Any idea?

I'm not sure there's a simple answer to this, and I think the answers may vary based on the type of replication. I think you may have to rely on heuristics to answer it.
For snapshot replication, I'm unable to think of anything that would give the game away. Obviously, the presence of the replication tables (e.g. MSreplication_objects) tells you that replication is occurring within the database, but there aren't any specific clues about tables, so far as I'm aware.
For transactional replication (non updating), you may be able to go via MSreplication_objects (which will list some stored procs) and then use sys.sql_dependencies to locate the tables that these relate to
For transaction replication (updating), you can look in MSsubscription_articles (or look for the presence of the subscription updating triggers against the table)
For merge replication, you can look in sysmergearticles, but you'd also have to look in sysmergesubscriptions to determine that you're on the subscription side.

Go to the subscriber database check for the table dbo.MSreplication_subscriptions. If the database is subscriber, you will find this table. Also, to find out articles use this in the subscribed database
SELECT publisher,Publisher_Db,publication,article
FROM dbo.MSreplication_objects

I used Damien the Unbeliever's idea (+1) to produce this code that worked for me
SELECT DISTINCT
ot.object_id
,ot.schema_id
,r.publisher
,r.publisher_db
,r.publication
,r.article
FROM
dbo.MSreplication_objects R
INNER JOIN sys.objects so ON r.object_name = so.name AND so.type = 'P' --stored procedures
INNER JOIN sys.sql_dependencies dp ON so.object_id = dp.object_id
INNER JOIN sys.objects ot ON dp.referenced_major_id = ot.object_id --objects
AND r.article = ot.name

Simplest way would be to create a linked server to the main server and query the table [distribution].[dbo].[MSarticles].
select * from [distribution].[dbo].[MSarticles]

Take a look at DATABASEPROPERTYEX. It has an 'IsSubscribed' option that should do what you want it to do.

Related

Automated way to get every table that's used in any View - INFORMATION_SCHEMA.VIEW_TABLE_USAGE is incomplete

I want to see every table in my Azure SQL database that is referenced in a View.
One would think this would work:
select distinct table_name from INFORMATION_SCHEMA.VIEW_TABLE_USAGE
But the table list is incomplete. There are tables missing, which I can manually verify are being called in Views.
Googling, I see others with the same issue, as well as people saying not to use INFORMATION_SCHEMA views, because they're not accurate. Note: Nothing specific to Azure SQL, just in general - posts saying it's inaccurate.
I see references to using sys.objects instead. But if I run
exec sp_helptext 'information_schema.view_table_usage
I see that the inaccurate view, is itself referencing sys.objects
Is there an automated, accurate way to see which tables are being used in a View, within a given database?
You can use sys.sql_expression_dependencies, which is generally more reliable.
SELECT *
FROM sys.sql_expression_dependencies d
WHERE d.referencing_id IN (SELECT v.object_id FROM sys.views)

Activity log of database MS SQL Server

I have a database with more than a hundred tables. I am continuously adding columns to existing tables (if required) and I also added few new tables.
Now I want to check what changes I have made in last 3 months. Is there any activity log in MS SQL Server 2012 for that specific database to track changes.
Perhaps this can get you partway. sys.objects has create and modify dates but unfortunately sys.columns does not. However the latest columns added will have higher column_ids. I don't know that you would be able to pick out deleted columns that easily. Note that changes other than column changes can be reflected by the modify date.
select s.name [schema], o.name [table], o.modify_date [table_modify_date], c.column_id, c.name
from sys.schemas s
join sys.objects o on o.schema_id = s.schema_id
left join sys.columns c on c.object_id = o.object_id
where o.type = 'U' --user tables only
and o.modify_date >= dateadd(M,-3, getdate())
order by s.name, o.name, column_id;
To make this audit easier in the future you can create a DDL trigger that will log all schema changes to a table or in source control if you use something like a SSDT data project to manage your changes.
Right now,your options are limited ,going forward you can try below and also check to see if they help you, now..
1.If you have enabled Audit,you can track the changes
To check ,if you have enabled Audit,You can use below query..
select * from sys.dm_server_audit_status
If you have not enabled Audit,you can enable it ,following this :An Introduction to SQL Server Audit..I would not recommend enabling Audit ,unless you need to capture other than what is mentioned in your question
2.Default trace also captures tables created ,but this uses, roll over files mechanism to override last files when the space is full,so you may be out of luck(since you are asking for three months range),but try this:What event information can I get by default from SQL Server? to find out to know all the things,which are offered by default trace
I would go with this option and try backing up those files ,depending on when they rollup(since you need only to check table changes)
3.Finally One final option is to query Tlog
select * from fn_dblog(null,null) where [transaction name]='CREATE TABLE'
the above Tlog option works only if you have Tlog backups for over three months and also you need to restore them
To Check all the activities in past time, you can work with MSSQL Audit. Its the best way to track any changes at any time. Please Check
https://msdn.microsoft.com/en-us/library/cc280386.aspx
You could run a report from the right click menu on the DB:
There are several reports that might interest you in this drop down. Or you could possibly create a custom report with just the information that you need.
My Schema report only goes back to 9/3/2016, but I have 1000+ tables with 60+ columns with many updates daily. Yours might go back further.
You could use a DDL Trigger:
CREATE TRIGGER ColumnChanges
ON DATABASE
FOR ALTER_TABLE
AS
DECLARE #data XML
SET #data = EVENTDATA()
INSERT alter_table_log
(PostTime, DB_User, Event, TSQL)
VALUES
(GETDATE(),
CONVERT(nvarchar(100), CURRENT_USER),
#data.value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(100)'),
#data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(2000)') ) ;
GO
If you have any backups going back 3 months, say on tape, you could restore a backup as a different name or to another server and then run a schema comparison via third party tool - Visual Studio, Devart Schema Compare, etc.
Otherwise preemptively setting up the mechanisms before you need them as described by Gameiswar and others is the only way.
Take snapshots of the metadata definitions via the "Generate Scripts..." Tasks option from the SQL Server Management Studio.
Store the generated script files in a folder whose name references the current date. Once this has been done more than once, WinDiff can be used to highlight the database changes made between any two snapshots. Choose the "Generate Scripts" options carefully and consistently so that time based comparisons are more beneficial.
This query will give the last date of creation and modified of Stored Procedures:
select name,create_date,modify_date
from sys.procedures
order by modify_date desc

SQL Server NOLOCK and joins

Background: I have a performance-critical query I'd like to run and I don't care about dirty reads.
My question is; If I'm using joins, do I have to specify the NOLOCK hint on those as well?
For instance; is:
SELECT * FROM table1 a WITH (NOLOCK)
INNER JOIN table2 b WITH (NOLOCK) ON a.ID = b.ID
Equivalent to:
SELECT * FROM table1 a WITH (NOLOCK)
INNER JOIN table2 b ON a.ID = b.ID
Or will I need to specify the (NOLOCK) hint on the join to ensure I'm not locking the joined table?
I won't address the READ UNCOMMITTED argument, just your original question.
Yes, you need WITH(NOLOCK) on each table of the join. No, your queries are not the same.
Try this exercise. Begin a transaction and insert a row into table1 and table2. Don't commit or rollback the transaction yet. At this point your first query will return successfully and include the uncommitted rows; your second query won't return because table2 doesn't have the WITH(NOLOCK) hint on it.
I was pretty sure that you need to specify the NOLOCK for each JOIN in the query. But my experience was limited to SQL Server 2005.
When I looked up MSDN just to confirm, I couldn't find anything definite. The below statements do seem to make me think, that for 2008, your two statements above are equivalent though for 2005 it is not the case:
[SQL Server 2008 R2]
All lock hints are propagated to all the tables and views that are accessed by the query plan, including tables and views referenced in a view. Also, SQL Server performs the corresponding lock consistency checks.
[SQL Server 2005]
In SQL Server 2005, all lock hints are propagated to all the tables and views that are referenced in a view. Also, SQL Server performs the corresponding lock consistency checks.
Additionally, point to note - and this applies to both 2005 and 2008:
The table hints are ignored if the table is not accessed by the query plan. This may be caused by the optimizer choosing not to access the table at all, or because an indexed view is accessed instead. In the latter case, accessing an indexed view can be prevented by using the OPTION (EXPAND VIEWS) query hint.
Neither. You set the isolation level to READ UNCOMMITTED which is always better than giving individual lock hints. Or, better still, if you care about details like consistency, use snapshot isolation.

Performance of inter-database query (between linked servers)

I have an import between 2 linked servers. I basically got to get the data from a multiple join into a table on my side.
The current query is something like this:
select a.*
from db1.dbo.tbl1 a
inner join db1.dbo.tbl2 on ...
inner join db1.dbo.tbl3 on ...
inner join db1.dbo.tbl4 on ...
inner join db2.dbo.myside on ...
db1 = linked server
db2 = my own database
After this one, I am using an insert into + select to add this data in my table which is located in db2. (usually few hundred records - this import running once a minute)
My question is related to performance. The tables on the linked server (tbl1, tbl2, tbl3, tbl4) are huge tables, with millions of records, and it is slowing down the import process.
I was told that, if I do the join on the "other" side (db1 - linked server) for example in a stored procedure, than, even if the query looks the same, it would run faster. Is that right? This is kinda hard to test. Note that the join contains a table from my database too.
Also. are there other "tricks" I could use in order to make this run faster? Thanks
It really depends on what your query is actually doing. You can use the "remote" hint on the joins to force the join to happen on the linked server. i.e.:
select a.*
from db1.dbo.tbl1 a
inner remote join db1.dbo.tbl2 on ...
inner remote join db1.dbo.tbl3 on ...
inner remote join db1.dbo.tbl4 on ...
inner join db2.dbo.myside on ...
(I assume you left the server out of the above and that all the "db1." references are really "linkedserver.db1".)
If you can do most of the work with just information on the linked server you can use OPENQUERY to speed things up. i.e.:
select a.*
from OPENQUERY(db1, 'SELECT a.* from db1.dbo.tbl1 a
inner join db1.dbo.tbl2 on ...
inner join db1.dbo.tbl3 on ...
inner join db1.dbo.tbl4 on ... ') a
inner join db2.dbo.myside on ...
But the best way to speed it up may be having a control table on the linked server to control what to return, but again it depends on your actual query, what it is doing, and what permissions you have on the linked server.
It is correct to place a stored procedure on db1 to improve performance, this way less data has to go over the pipe, since a lot is filtered in the joins.
If the data on the other side is static, why not place it into a materialized view? This way you only have to update the data once a day instead of each time the query is executed.
Stored procedures are cached, hence the first time you run the stored procedure it will take some time. All further calls to that stored procedure will execute a lot faster. You can see the performance impact by including the execution statistic in your SSMS.
To improve the join performance make sure you have indexes in place.
Notice that cross server inserts are dangerous since you are relying on the network. I'm also not sure whether you can use transactions in this scenario. If not, than it's another problem.
I have seen a scenario where temp database wasn't able to cope with the such an insert, and the fix was to use a cursor. This is was much slower, but more reliable for that scenario.

SQL Server replication question

I had inherited this SQL Server where we put data in a table (Call TableA) on a database (DB-A). I can see the tableA in another database on the same server ( DB-B) gets the same data right away.
Any ideas how this is implemented? I am trying to see the trace but so far no luck. Any one has an idea?
At this stage I am not sure if its replication. This is a guess
It could be replication or it could be a trigger on the source table that is moving the data over.
Perhaps it is transactional replication? You should be able to go to the replication are and see if there are subscribers or publishers.
Either that or you have linked servers, and triggers are copying the data.
This is most likely happening by use of either a synonym or cross-database view. Check to see if the "table" on the other database really is a table. If it IS a table, then they've set up transactional replication between the two databases.
select type_desc from sys.objects where name = 'name_on_database_b'