Does anyone know a way to see the Compression level through the Calculate button without having to go through each table 1-by-1?
You can call sp_estimate_data_compression_savings for each table, specifying the desired compression level. Below is an example script that uses a cursor for the task, inserting the results of each table into a table variable and the final results of all tables via a select query.
USE YourDatabase;
SET NOCOUNT ON;
DECLARE #estimated_compression TABLE(
object_name sysname,
schema_name sysname,
index_id int,
partition_number int,
size_with_current_compression_setting_kb bigint,
size_with_requested_compression_setting_kb bigint,
sample_size_with_current_compression_setting_kb bigint,
sample_size_with_requested_compression_setting_kb bigint
);
DECLARE #schema_name sysname, #object_name sysname;
DECLARE tables CURSOR LOCAL FAST_FORWARD READ_ONLY FOR
SELECT s.name AS schema_name, t.name AS table_name
FROM sys.schemas AS s
JOIN sys.tables AS t ON t.schema_id = s.schema_id;
OPEN tables;
WHILE 1 = 1
BEGIN
FETCH NEXT FROM tables INTO #schema_name, #object_name;
IF ##FETCH_STATUS = -1 BREAK;
INSERT INTO #estimated_compression
EXEC sp_estimate_data_compression_savings
#schema_name = #schema_name
, #object_name = #object_name
, #index_id = NULL
, #partition_number = NULL
, #data_compression = 'PAGE';
END
CLOSE tables;
DEALLOCATE tables;
SELECT *
FROM #estimated_compression
ORDER BY object_name, schema_name, index_id, partition_number;
GO
Related
I have to check for value existence in a subset of tables in a subset of databases of a sql server instance. Beware I need to do this because I have 30 databases with same schema name and similar structure. Querying all databases separately is a waste of time.
The query generates correctly code for existing tables, but the additional check for column existence in table fails.
The column in some tables does not exist so the generated code must not include queries on tables without this column.
To solve this I need to realiably find a way to join sys.databases with sys.tables and then sys.columns. Or an alternative way to query all the required databases in a time saving manner.
SET NOCOUNT ON;
IF OBJECT_ID (N'tempdb.dbo.#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp
(
exist INT
, DB VARCHAR(50)
, tbname VARCHAR(500)
)
/*tables common root,
all tables i need to query start with this prefix and a number between 1 and 50
and some resulting tables do not exist
ex: dbo.Z_WBL_ASCHEDA23 exist in wbcto, while dbo.Z_WBL_ASCHEDA23 does not exist in db wbgtg
*/
DECLARE #TableName NVARCHAR(200)
SELECT #TableName = 'dbo.Z_WBL_ASCHEDA'
DECLARE #SQL NVARCHAR(MAX)
;WITH n(n) AS
(
SELECT 1
UNION ALL
SELECT n+1 FROM n WHERE n < 50
)
SELECT #SQL = STUFF((
SELECT CHAR(13)+'SELECT COUNT(1), ''' + db.name + ''', '''+
#TableName+CONVERT(VARCHAR, n.n)+''' FROM ' +#TableName+CONVERT(VARCHAR, n.n)
+ ' WHERE COALESCE(s_dettagli,'''') = ''CONTROLLATO'' '
+CHAR(13)
FROM sys.databases db
INNER JOIN n ON 1=1
INNER JOIN sys.tables t ON OBJECT_ID(db.name + '.' + #TableName+CONVERT(VARCHAR, n.n)) IS NOT NULL
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID and c.name = 's_dettagli'
/*join on columns not working, generates sql for tables without 's_dettagli' column and query fails*/
WHERE db.name like 'wb%' --check only databases starting with 'wb'
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
select #SQL
INSERT INTO #temp (exist, DB, tbname)
EXEC sys.sp_executesql #SQL
SELECT *
FROM #temp t
where exist <> 0
EDIT: adding some sql generated from query
SELECT COUNT(1), 'wb360', 'dbo.Z_WBL_ASCHEDA23' FROM wb360.dbo.Z_WBL_ASCHEDA23 WHERE COALESCE(s_dettagli,'') = 'CONTROLLATO'
SELECT COUNT(1), 'Wbbim', 'dbo.Z_WBL_ASCHEDA32' FROM Wbbim.dbo.Z_WBL_ASCHEDA32 WHERE COALESCE(s_dettagli,'') = 'CONTROLLATO'
the table of first query doesn't contain 's_dettagli' column
EDIT2: SOLUTION
EXEC sp_MSforeachdb '
IF ''?'' not like ''wb%''
RETURN
USE [?]
EXEC sp_MSforeachtable
#replacechar = ''!'',
#command1 = ''SELECT ''''?'''' AS db_name, ''''!'''' AS table_name, COUNT(*) FROM ! '',
#whereand = '' And Object_id In (
Select t.Object_id
From sys.objects t
INNER JOIN sys.columns c on c.Object_id = t.Object_id
Where t.name like ''''Z_WBL_ASCHEDA%''''
AND c.name = ''''s_dettagli'''' )'' '
Sys.columns can be joined to sys.tables using the object_id field (the object_id is the representation of the table itself).
sys.tables is run in the context of the database you are querying, hence you cannot see a table contained in another database. sys.databases can be run on any database on an instance and allow you to view other databases on the same instance. As such you don't need to join the table to the database (also the reason why there is no database_id field within sys.tables).
I hope that helps. Any clarification please let me know.
I would suggest alternative ways:
use registered Servers in SSMS and run the script on each database here
use exec sys.sp_MSforeachdb here
use sqlcmd and powershell to switch databases
I believe this script can help you :
SET NOCOUNT ON;
IF OBJECT_ID (N'tempdb.dbo.#Temp') IS NOT NULL
DROP TABLE #Temp
CREATE TABLE #Temp
(
exist INT
, DB VARCHAR(50)
, tbname VARCHAR(500)
)
DECLARE #SchemaName NVARCHAR(200)
DECLARE #TableName NVARCHAR(200)
DECLARE #ColumnName NVARCHAR(200)
DECLARE #SearchText NVARCHAR(200)
DECLARE #DBNameStartWith NVARCHAR(200)
DECLARE #SQL NVARCHAR(MAX)
SET #DBNameStartWith = 'wb'
SET #SchemaName = 'dbo'
SET #TableName = 'Z_WBL_ASCHEDA'
SET #ColumnName = 's_dettagli'
SET #SearchText = 'CONTROLLATO'
DECLARE #DatabaseName varchar(100)
DECLARE Crsr CURSOR FOR
SELECT name
FROM MASTER.sys.sysdatabases
WHERE name LIKE ''+#DBNameStartWith+'%'
OPEN Crsr
FETCH NEXT FROM Crsr INTO #DatabaseName
WHILE ##FETCH_STATUS = 0
BEGIN
IF ISNULL((SELECT COUNT(1) FROM SYS.TABLES T,SYS.COLUMNS C WHERE T.object_id=C.object_id AND T.name=#TableName AND C.name=#ColumnName),0)>0
BEGIN
SET #SQL = '
IF EXISTS (SELECT 1 FROM '+#DatabaseName+'.SYS.TABLES T,'+#DatabaseName+'.SYS.COLUMNS C WHERE T.object_id=C.object_id AND T.name='''+#TableName+''' AND C.name='''+#ColumnName+''')
BEGIN
SELECT COUNT(1),'''+#DatabaseName+''','''+#TableName+'''
FROM '+#DatabaseName+'.'+#SchemaName+'.'+#TableName+'
WHERE '+#ColumnName+'=''' +#SearchText+'''
END'
PRINT(#SQL)
INSERT INTO #Temp
EXEC sp_executesql #SQL
END
FETCH NEXT FROM Crsr INTO #DatabaseName
END
CLOSE Crsr
DEALLOCATE Crsr
SELECT * FROM #Temp
I want to execute the below query against all databases.
DECLARE #DB_NAME VARCHAR(30)
SET #DB_NAME = 'Employee';
WITH D
AS
(
SELECT #DB_NAME AS DB_NAME, T.NAME AS TABLE_NAME, C.NAME AS COLUMN_NAME
FROM SYS.tables T
INNER JOIN SYS.columns C
ON T.object_id = C.object_id
WHERE C.name LIKE '%AFFINITY%'
or c.name = 'affinity'
)
SELECT DB_NAME, TABLE_NAME, MAX(COLUMN_NAME) AS COLUMN_NAME FROM D
GROUP BY DB_NAME, TABLE_NAME
ORDER BY TABLE_NAME`
There is the undocumented
EXEC sp_MSforeachdb #command
(A ? in the command will be replaced by the DB name.)
Otherwise you'll need sp_executesql and a cursor over sys.databases.
The latter is supported, sp_MSforeachdb isn't, so for any kind of production system the cursor is the better option (even if a little more work initially). And of course your own query on sys.databases can filter the database list.
USE CAREFULLY:
I assume you have a MYTABLE in each required database, otherwise this wont work.
DECLARE #MYDATABASES NVARCHAR(50)
CREATE TABLE #MYBASE(DB NVARCHAR(50))
DECLARE dbcur CURSOR FOR
SELECT name
FROM sys.databases s
WHERE name not in ('master', 'tempdb', 'msdb') --use this to select all databases but system
--WHERE NAME IN ('myfirstDB', 'mysecondDB', 'mythirdDB') --use this to select only certain databases
OPEN dbcur
FETCH dbcur INTO #MYDATABASES
WHILE ##FETCH_STATUS = 0
BEGIN
/* MY STATEMENT */
DECLARE #SQLSTATEMENT NVARCHAR(MAX)
SELECT #SQLSTATEMENT = N'
SELECT #DB --EDIT WITH YOUR COLUMNS
FROM '+#MYDATABASES+'.dbo.MYTABLE --EDIT THIS
'
INSERT INTO #MYBASE
EXEC sp_executesql #SQLSTATEMENT, N'#DB NVARCHAR(50)', #DB = #MYDATABASES
/* END STATEMENT */
FETCH NEXT FROM dbcur INTO #MYDATABASES
END
CLOSE dbcur
DEALLOCATE dbcur
SELECT DISTINCT * FROM #MYBASE
ORDER BY DB
DROP TABLE #MYBASE
I did this. But unfortunately that return all in many table. I want to return all in one unique table. Maybe using "UNION" but I don't know the way to do.
This is my code:
EXEC sp_msforeachdb 'select ''?''AS "DataBase", s.name, t.name AS "Tables",max(si.rows) as "Rows Line"
from [?].sys.tables t inner join [?].sys.schemas s
on t.schema_id = s.schema_id
inner join [?].sys.partitions si on t.object_id = si.object_id
where t.name like "%ATTACH" group by s.name,t.name'`
You cannot do it in a single query.
You could query the sys.databases table to get a temporary table of all your databases, and then run a dynamic query on each database to store the results of the query in your question all in another temporary table.
Then at the end, you just select all rows from the last temporary table.
I have found finally a solution.i just used a Stored Procedures for having the result i was looking for.So decided to post the answer here maybe that will help someone else.
DECLARE #banco_nome nvarchar(MAX), #tabela_nome nvarchar(MAX)
DECLARE #banco_cursor CURSOR
DECLARE #sqlstatement nvarchar(MAX)
DECLARE #count_sql nvarchar(MAX)
DECLARE #total int
DECLARE #RegistrosFotograficos TABLE
(
DatabaseName nvarchar(max),
TableName nvarchar(max),
Total int
)
SET #banco_cursor = CURSOR FORWARD_ONLY FOR
SELECT name FROM sys.databases
OPEN #banco_cursor
FETCH NEXT FROM #banco_cursor INTO #banco_nome
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sqlstatement = 'DECLARE tabela_cursor CURSOR FORWARD_ONLY FOR SELECT TABLE_NAME FROM ' + #banco_nome + '.INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = ''BASE TABLE'' AND TABLE_NAME LIKE ''%ATTACH'' ORDER BY TABLE_NAME'
EXEC sp_executesql #sqlstatement
OPEN tabela_cursor
FETCH NEXT FROM tabela_cursor INTO #tabela_nome
WHILE ##FETCH_STATUS = 0
BEGIN
SET #count_sql = 'USE ' + #banco_nome + '; SELECT #total=COUNT(1) FROM ' + #tabela_nome;
EXECUTE sp_executesql #count_sql, N'#total int OUTPUT', #total=#total OUTPUT
INSERT INTO #RegistrosFotograficos (DatabaseName, TableName, Total) VALUES (#banco_nome, #tabela_nome, #total);
FETCH NEXT FROM tabela_cursor INTO #tabela_nome
END
CLOSE tabela_cursor;
DEALLOCATE tabela_cursor;
FETCH NEXT FROM #banco_cursor INTO #banco_nome
END
CLOSE #banco_cursor;
DEALLOCATE #banco_cursor;
SELECT * FROM #RegistrosFotograficos
This will list all the tables in a given database and the number of rows in each. Notice the results are in a table named #results:
set nocount on
declare #curtable sysname
declare #prevtable sysname
declare #curcount int
declare #tsql varchar(500)
if object_ID('tempdb..#curtables','U') is not null
drop table #curtables
select name into #curtables
from sys.objects
where type='U'
order by 1
if object_id('tempdb..#results','U') is not null
drop table #results
create table #results(name sysname,numrows int)
select top 1 #curtable=name from #curtables order by name
while (1=1)
begin
set #tsql = 'select '''+quotename(#curtable) +''',count(*) numrows from '+quotename(#curtable)
print #tsql
insert into #results
exec (#tsql)
set #prevtable= #curtable
select top 1 #curtable = name
from #curtables
where name > #prevtable
order by name
if #curtable=#prevtable
break
end
I have 40 Tables - Table1, Table2 , Table3 ... Table40, all having same columns .
These tables contains distinct data and to identify each table's data , I have a column Reporting_Type which have different value for each table.
For example: column Reporting_Type of Table1 has value Reportin_Type1 and so on.
Please note that each table contains 2-3 million records.
I need to create a view which combines the data from all the tables.
I have simply applied UNION ALL and put the following query :
CREATE VIEW ALL DATA
AS
SELECT
COLUMN1, COLUMN2, COLUMN3, REPORTING_TYPE ..., COLUMN 40
FROM
TABLE1
UNION ALL
SELECT
COLUMN1, COLUMN2, COLUMN3, REPORTING_TYPE ..., COLUMN 40
FROM
TABLE2
UNION ALL
SELECT
COLUMN1, COLUMN2, COLUMN3, REPORTING_TYPE ..., COLUMN 40
FROM
TABLE3
....
SELECT
COLUMN1, COLUMN2, COLUMN3, REPORTING_TYPE ..., COLUMN 40
FROM
TABLE40
The above query takes a lot of time to fetch the data from all the tables.
Could any please suggest any performance tuned query or any other way to create this view in SQL Server 2012?
Apologies if any one find this question too Naive. I am new to database. Kindly let me know if more information is required.
I kindly recommend Clustered Indexes on those table, so should have primary key in all of the tables, if there is a primary key with those tables, try to rebuild or reorganize indexes,to rebuild and reorganize you could also refer below script. Without any cluster index and where condition it would be scan but with Clustered index you would get better performance.
-- Make Sure you have write USE <databasename> statement before executing statement.
-- USE <databasename>
SET NOCOUNT ON;
DECLARE #objectid int;
DECLARE #indexid int;
DECLARE #partitioncount bigint;
DECLARE #schemaname nvarchar(500);
DECLARE #objectname nvarchar(500);
DECLARE #indexname nvarchar(500);
DECLARE #partitionnum bigint;
DECLARE #partitions bigint;
DECLARE #frag float;
DECLARE #command nvarchar(4000);
-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function
-- and convert object and index IDs to names.
SELECT
object_id AS objectid,
index_id AS indexid,
partition_number AS partitionnum,
avg_fragmentation_in_percent AS frag
INTO #work_to_do
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED')
WHERE index_id > 0;
-- Declare the cursor for the list of partitions to be processed.
DECLARE partitions CURSOR FOR SELECT * FROM #work_to_do;
-- Open the cursor.
OPEN partitions;
-- Loop through the partitions.
WHILE (1=1)
BEGIN;
FETCH NEXT
FROM partitions
INTO #objectid, #indexid, #partitionnum, #frag;
IF ##FETCH_STATUS < 0 BREAK;
SELECT #objectname = QUOTENAME(o.name), #schemaname = QUOTENAME(s.name)
FROM sys.objects AS o
JOIN sys.schemas as s ON s.schema_id = o.schema_id
WHERE o.object_id = #objectid;
SELECT #indexname = QUOTENAME(name)
FROM sys.indexes
WHERE object_id = #objectid AND index_id = #indexid;
SELECT #partitioncount = count (*)
FROM sys.partitions
WHERE object_id = #objectid AND index_id = #indexid;
-- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding.
IF #frag < 30.0 OR #frag >= 5.0
SET #command = N'ALTER INDEX ' + #indexname + N' ON ' + #schemaname + N'.' + #objectname + N' REORGANIZE';
IF #frag >= 30.0 OR #frag < 5.0
SET #command = N'ALTER INDEX ' + #indexname + N' ON ' + #schemaname + N'.' + #objectname + N' REBUILD';
IF #partitioncount > 1
SET #command = #command + N' PARTITION=' + CAST(#partitionnum AS nvarchar(10));
EXEC (#command);
PRINT N'Executed: ' + #command;
END;
-- Close and deallocate the cursor.
CLOSE partitions;
DEALLOCATE partitions;
-- Drop the temporary table.
DROP TABLE #work_to_do;
GO
I also recommend to use cross apply, which is explained in StackOverflow's another thread
SNAHi
anyone please suggest a query in sql to find the unused tables.
I have a legacy application migrated to .net from coldfusion.But lots of tables are unused now
What is the best way to find all the unused objects from database. (sql 2005)
thanks
SNA
In SQL Server, the acutal table data IS the clustered index. Using this query on the Dynamic Management Views (DMV) in SQL Server 2005 and up, you can find unused indices - if you find any clustered index (index_id=1) being unused over an extended period of time, the table is not being used anymore:
DECLARE #dbid INT
SELECT #dbid = DB_ID(DB_NAME())
SELECT
OBJECTNAME = OBJECT_NAME(I.OBJECT_ID),
INDEXNAME = I.NAME,
I.INDEX_ID
FROM
SYS.INDEXES I
JOIN
SYS.OBJECTS O ON I.OBJECT_ID = O.OBJECT_ID
WHERE
OBJECTPROPERTY(O.OBJECT_ID, 'IsUserTable') = 1
AND I.INDEX_ID NOT IN
(SELECT S.INDEX_ID
FROM SYS.DM_DB_INDEX_USAGE_STATS S
WHERE S.OBJECT_ID = I.OBJECT_ID
AND I.INDEX_ID = S.INDEX_ID
AND DATABASE_ID = #dbid)
ORDER BY
OBJECTNAME,
I.INDEX_ID,
INDEXNAME ASC
Another option would be to temporarily rename a table if you suspect it's not being used, and then see if your app(s) still work as expected. If they do for e.g. 30 days or so, then you're pretty sure you don't need that table anymore.
Marc
-- Query to find the tables not used by any stored procedure, function nor view
-- Using SQL 2005 system tables, all programatical objects for dependencies, and one&only query:
select tables.name, progr.name
from sys.objects tables (nolock)
left join sys.syscomments comm (nolock) on comm.text like '%' + tables.name +'%'
left join sys.objects progr (nolock) on progr.object_id = comm.id and progr.type in ('P', 'FN', 'TR', 'V' )
where tables.type = 'U'
and comm.id is null
Here is a query i have written to find the tables not used by any store procedures..
......................................................................................
Declare #tablename nvarchar(40)
Declare tablecursor cursor for
Select name from sysobjects where xtype = 'U'
DECLARE #sqlCommand nvarchar(1000)
declare #rowCount int
DECLARE #searchstring varchar(50)
DECLARE #ParmDefinition nvarchar(500);
create table #temp
(
UnusedTables nvarchar(40)
)
open tablecursor
fetch next from tablecursor into #tablename
while ##fetch_status = 0
begin
set #searchstring='p'
SET #sqlCommand = N'SELECT #rows = count(o.name) from sysobjects o ,
syscomments c where o.type='+char(39)+#searchstring + char(39)+' and
o.id=c.id and c.text like '+ char(39)+'%' + #tablename +'%'+char(39);
SET #ParmDefinition = N'#rows int OUTPUT';
EXECUTE sp_executesql #sqlCommand, #ParmDefinition,#rows=#rowCount OUTPUT;
if #rowCount = 0
begin
insert into #temp values (#tablename)
end
fetch next from tablecursor into #tablename
end
close tablecursor
deallocate tablecursor
select UnusedTables from #temp
drop table #temp
thanks
SA
Try something like below
DECLARE #TableNameTemp TABLE
(
id INT IDENTITY (1, 1),
tablename VARCHAR(1000)
)
INSERT INTO #TableNameTemp
SELECT table_name
FROM information_schema.tables
WHERE table_type = 'BASE TABLE'
ORDER BY table_name
DECLARE #CursorTestID INT = 1;
DECLARE #TotalCount INT = (SELECT Count(1)
FROM #TableNameTemp)
DECLARE #FinalResult TABLE
(
unsedtables VARCHAR(max)
)
DECLARE #TemExecInsert TABLE
(
testvalue VARCHAR(max),
type VARCHAR(max)
)
DECLARE #TableaName VARCHAR(max) = ''
WHILE #CursorTestID <= #TotalCount
BEGIN
DELETE FROM #TemExecInsert
SET #TableaName = (SELECT tablename
FROM #TableNameTemp
WHERE id = #CursorTestID)
INSERT INTO #TemExecInsert
EXEC Sp_depends
#objname = #TableaName
SET #CursorTestID = #CursorTestID + 1
IF ( (SELECT Count(1)
FROM #TemExecInsert) = 0 )
BEGIN
INSERT INTO #FinalResult
VALUES (#TableaName)
END
END
SELECT *
FROM #FinalResult
PS: Sorry, I am not certain how to bring the answer in shape. Hope this helps