As we live in a World of "delivery first", we now found our self with databases that are infected by tons of index hints.
I wrote a query that might help me find out all the WITH (INDEX= in the database:
SELECT
DB_NAME() AS DB_NAME,
name AS Object_Name,
type_desc AS Object_Type,
definition
FROM
sys.sql_modules
INNER JOIN
sys.objects ON sys.sql_modules.object_id = sys.objects.object_id
WHERE
definition LIKE '%(INDEX=%';
but as the definition column is sometimes too long to read I would like to select from that column just, let's say, 30 characters before and 30 characters after the WITH (INDEX=.
How to select just that part of the string?
Basically in that column I just would like to see:
...INNER JOIN tblSession WITH (INDEX=indRealDateTime) ON ...
which is the part of the query I'm interested in. I want to see at a glance how painful is that index hint.
Demo Example,
declare #i varchar(500)='afgdfgdfgdfg dgfdgdfg dfgdfgdfg dfgdfgdfg cvxfsdfsdfdf erwererwer (index fgfdgdf weqweqweqwe dsadsads sfsfsdfd erewwerwer 6786787 35345dfsdfgsdfsdf sdfdsfsdfdf'
DECLARE #margin INT = 15 --try 15000
SELECT SUBSTRING(#i, charindex('index', #i) - #margin, charindex('index', #i) + #margin)
Related
I was assigned to see if all of the current tables in a database are used and if not to drop them. These are the steps I have taken so far:
Searched tables names in the program that uses that database to see if a query has been made in the program based on those tables names.
Investigated if a table primary key has been used in any other places such as view or table (Connectivity with other used tables). I used:
SELECT
t.name AS table_name,
SCHEMA_NAME(schema_id) AS schema_name,
c.name AS column_name
FROM
sys.tables AS t
INNER JOIN
sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
WHERE
c.name LIKE 'DeflectionId' -- write the column you search here
ORDER BY
schema_name, table_name;
Searched inside all of the stored procedure texts to see if a table name has been used inside them:
SELECT DISTINCT
o.name AS Object_Name,
o.type_desc
FROM
sys.sql_modules m
INNER JOIN
sys.objects o ON m.object_id = o.object_id
WHERE
m.definition LIKE '%\[Test_Results_LU\]%' ESCAPE '\';
or
SELECT name
FROM sys.procedures
WHERE Object_definition(object_id) LIKE '%Test_Results_LU%'
(from this link: Search text in stored procedure in SQL Server )
Used Object Explorer view to see if a table with the similar/same name and size exists in the database.
Do you think there are other ways that I can use to investigate it better?
Are these steps efficient at all? How would you do it?
Those are all reasonable things to check. One more thing to do would be to turn on profiling or auditing, depending on your SQL server version, and actually monitor for the tables being used for a reasonable time period. You may not be able to do that with a production system, and it's still not 100% guaranteed - what if there's an important table that's only queried once a year?
https://dba.stackexchange.com/questions/40960/logging-queries-and-other-t-sql
https://learn.microsoft.com/en-us/sql/relational-databases/security/auditing/view-a-sql-server-audit-log?view=sql-server-2017
One other suggestion before dropping the tables is to explicitly remove access to them (either with DENY/REVOKE or rename them to table-name_purge) for a week or two and see if anyone complains. If they don't, then it's probably safe to make a backup and then drop them.
A couple of other places to check. Both of these rely on data that is
cached automatically by the system
not persisted between restarts
can be dropped at any time.
so absence from these results does not prove that the table is not used but you may find evidence that a table definitely is in use.
SELECT [Schema] = OBJECT_SCHEMA_NAME(object_id),
[ObjectName] = OBJECT_NAME(object_id),
*
FROM sys.dm_db_index_usage_stats
WHERE database_id = DB_ID()
And in the plan cache
USE YourDB
DROP TABLE IF EXISTS #cached_plans, #plans, #results
DECLARE #dbname nvarchar(300) = QUOTENAME(DB_NAME());
SELECT dm_exec_query_stats.creation_time,
dm_exec_query_stats.last_execution_time,
dm_exec_query_stats.execution_count,
dm_exec_query_stats.sql_handle,
dm_exec_query_stats.plan_handle
INTO #cached_plans
FROM sys.dm_exec_query_stats;
WITH distinctph
AS (SELECT DISTINCT plan_handle
FROM #cached_plans)
SELECT query_plan,
plan_handle
INTO #plans
FROM distinctph
CROSS APPLY sys.dm_exec_query_plan(plan_handle);
WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
SELECT cp.*,
st.text,
[Database] = n.value('#Database', 'nvarchar(300)'),
[Schema] = n.value('#Schema', 'nvarchar(300)'),
[Table] = n.value('#Table', 'nvarchar(300)')
INTO #results
FROM #cached_plans cp
JOIN #plans p
ON cp.plan_handle = p.plan_handle
CROSS APPLY sys.dm_exec_sql_text(sql_handle) st
CROSS APPLY query_plan.nodes('//Object[#Database = sql:variable("#dbname") and #Schema != "[sys]"]') qn(n);
SELECT *
FROM #results
I have a problem.
I want to show field_name at my query 'select .. from .. where' clause.
In my logging table, the table only keep the [date],[table_id],[field_id] .. fields, i need to show the 'field_name' as well in my select but there is no any other table that i can 'join' to get the [field_name] based on [field_id] in my 'select .. from'. As I search from google it seems I can get the field_name from SQL system called 'sys.columns' table. but that is too complicated for my SQL level because this sys.coloums is not straight forward. it mixed all the table before all each field number depend on the table id itself.
anyone who know how to write a good query to select out the field_name pls help :)
log_list table
[date],[table_id],[field_id],[company_name],...
my current query :
SELECT
date , table_id , name as table_name
FROM
log_list join table_name_list on log_list.table_id = table_name_list.table_id
and log_list.company_name like '%something%'
WHERE
date between #startdate and #enddate
thank you for your attention.
Your tag didn't say what version of SQL Server you are using, assuming you are using 2008+ there is a system function
COL_NAME ( table_id , column_id )
which if you supply table_id and column_id would get you the name, for detailed reference check it out here: COL_NAME (Transact-SQL)
If that is not a valid option for you, look closer to sys.columns, the object_id it returns is actually the table's object_id and should be your table_id, so if you do something like following it should work:
select C.name AS column_name
...
FROM ...
...
join sys.columns C on yourtable.table_id = C.object_id and yourtable.column_id = C.column_id
I have just come across a curious SQL Server behaviour.
In my scenario I have a sort of dynamic database, so I need to check the existence of tables and columns before run queries involving them.
I can't explain why the query
IF 0 = 1 -- Check if NotExistingTable exists in my database
BEGIN
SELECT NotExistingColumn FROM NotExistingTable
END
GO
executes correctly, but the query
IF 0 = 1 -- Check if NotExistingColumn exists in my ExistingTable
BEGIN
SELECT NotExistingColumn FROM ExistingTable
END
GO
returns Invalid column name 'NotExistingColumn'.
In both cases the IF block is not executed and contains an invalid query (the first misses a table, the second a column).
Is there any reason why SQL engine checks for syntax erorrs just in one case?
Thanks in advance
Deffered name resolution:
Deferred name resolution can only be used when you reference nonexistent table objects. All other objects must exist at the time the stored procedure is created. For example, when you reference an existing table in a stored procedure you cannot list nonexistent columns for that table.
You can look through the system tables for the existence of a specific table / column name
SELECT t.name AS table_name,
SCHEMA_NAME(schema_id) AS schema_name,
c.name AS column_name
FROM sys.tables AS t
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
WHERE c.name LIKE '%colname%'
AND t.name LIKE '%tablename%'
ORDER BY schema_name, table_name;
The query above will pull back all tables / columns with partial match of a columnname and tablename, just change the like % for exact match.
I am trying to join records in sys.columns for a view, to the records in sys.columns for the table it is referencing, because i need the values of is_nullable, is_computed and default_object_id columns for the columns that are selected in the view.
The sys.columns records for the view have "incorrect" values, which you can observe by running the example queries below:
CREATE TABLE TestTable (
FieldA int NOT NULL,
FieldB int DEFAULT (1),
FieldC as CONVERT(INT, FieldA + FieldB),
FieldD int NOT NULL
)
GO
CREATE VIEW TestView WITH SCHEMABINDING AS
SELECT FieldA, FieldC as TestC, FieldB + FieldC as TestD
FROM dbo.TestTable WHERE FieldD = 1
GO
SELECT OBJECT_NAME(c.object_id) as ViewName, c.name as ColumnName,
c.is_nullable as Nullable, c.is_computed as Computed,
cast(CASE WHEN c.default_object_id > 0 THEN 1 ELSE 0 END as bit) as HasDefault
FROM sys.columns c
WHERE object_id = OBJECT_ID('TestTable')
GO
SELECT OBJECT_NAME(c.object_id) as ViewName, c.name as ColumnName,
c.is_nullable as Nullable, c.is_computed as Computed,
cast(CASE WHEN c.default_object_id > 0 THEN 1 ELSE 0 END as bit) as HasDefault
FROM sys.columns c
WHERE object_id = OBJECT_ID('TestView')
GO
I have tried using system views to join on dependencies, but they do not give us information about which column in the view refers to which column in the table:
-- dm_sql_referenced_entities gives us all columns referenced, but all records
-- have referencing_minor_id 0, so we do not know which column refers to what
SELECT * FROM sys.dm_sql_referenced_entities('dbo.TestView', 'OBJECT')
GO
-- sql_dependencies gives us all columns referenced, but all records has
-- column_id 0 so we can not use this either of joining the columns
SELECT * FROM sys.sql_dependencies WHERE object_id = OBJECT_ID('TestView')
GO
-- sql_expression_dependencies just tells us what table we are referencing
-- if view is not created WITH SCHEMABINDING. If it is, it will return columns,
-- but with referencing_minor_id 0 for all records, so not able use this either
SELECT * FROM sys.sql_expression_dependencies
WHERE referencing_id = OBJECT_ID('TestView')
GO
This unanswered post on social.msdn submitted by someone seems to be the same issue:
http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/4ae5869f-bf64-4eef-a952-9ac40c932cd4
You said "i need to know that TestView TestC refers to a computed column". This is not supported by SQL Server 2008 R2 (not sure for 2012 though, but i doubt it).
First you can query sys.columns or INFORMATION_SCHEMA.COLUMNS and you won't find what you want.
If you dig deeper, you will most probably try sys.sql_expression_dependencies and sys.dm_sql_referenced_entities (N'dbo.TestView', N'OBJECT'), but you can find table-column mapping there, not column-column. SQL server stores dependency information by 'high level' object (table, trigger...), not by its details (column). You will find same in sys.sysdepends. As a matter of fact dependency information is in SQL server unreliable.
At last, your only possibility would be to parse the view body by yourself. It can be found in sys.sql_modules:
SELECT m.definition
FROM
sys.objects o
JOIN sys.sql_modules m
ON m.object_id = o.object_id
WHERE
o.object_id = object_id('dbo.TestView')
and o.type = 'V'
Parsing T-SQL is VERY hard, it could really push you to the limit of your efforts. For instance, it should be more or less easy to grab table references from the view, and then table columns, especially if your view is schema-bound. But if it's not, well... just think of asterisks that reference OUTER APPLY, which references recursive CTE...
Anyway, good luck!
Currently, when views are created there are two operations that happen at a high level - parsing & binding. Parsing is basically checking for syntax of the statement, keywords & such. Binding is the process of mapping the identifiers (object names, column names) in the statement to the corresponding objects (tables, views, functions, columns etc.) & derivation of types. Additionally, in case of view similar to SELECT statements you can optionally alias column references and expressions in the SELECT list or after the view name (ex: create view v1(a) as select i from t).
After binding, we persist only the column aliases & the derived types in the metadata since a view is logically a table derived from a query expression. So there is currently no way to determine the expression that the column aliases map to or what it contains (columns or functions or literals etc.)
Only way to obtain the information you are looking for is to parse the view definition & perform your own binding. I believe we already have a bug that tracks the feature request to expose more richer dependency information regarding the mapping of aliases to column expressions in view definitions.
Lastly, SQL Server Developer Studio or Visual Studio Database Project uses the managed T-SQL parser to track such references so you can do refactoring or renaming for example using the project.
Hope this helps clarify the problem/current implementation.
It seems like the misunderstanding is the assumption that object_id is a primary key in sys.columns. It is not. The object_id in sys.columns relates to the object_id in sys.objects.
So:
SELECT C.*
FROM sys.objects T
INNER JOIN sys.columns C
ON T.object_id = C.object_id
WHERE T.type in ('S','U') -- System Tables and User Tables
AND T.name = 'Address' -- Table Name
order by C.Column_ID
will return the columns in the "Address" table in AdventureWorks.
Consider a simple join:
Select TableB.*
From TableA
Inner Join TableB
On TableB.ID = TableA.ID
What I want to do is decide which table to join to depending on a parameter. Although the following syntax is not valid, I wrote it just to illustrate what I am after:
Select TableD.*
From TableA
Inner Join
[If #useTableC = 1 Then Join to TableC Else Join to TableB] As TableD
Both TableB and TableC have identical columns.
How can I create this kind of join. Please be aware that this example is actually a small portion of a much larger query so you cannot just use If...Else statements.
Thanks a lot!
Usually I'd prefer to rewrite in more than one statement, but if you really need it:
SELECT td.*
FROM TableA ta
JOIN (
SELECT tc.* FROM TableC Where #useTableC = 1
UNION ALL
SELECT tb.* FROM TableB Where #useTableC = 0
) td ON ( /* JOIN CONDITION MISSING */)
Unfortunately, T-SQL has no syntax to support this. I tinkered with this some time ago and couldn't come up with a solution, until I found this article that helped me (by using Left Outer joins) and it might help you. It is located here.
#Gerardo Lima's answer is excellent, but as an alternative you could build up your query with dynamic SQL. This would let you use a series of if statements to add, or not, as many joins as you wish using as many if statements as needed. As a coarse and rough example:
declare #sql varchar(8000)
set #sql = 'Select TableD.* From TableA '
if #usertableC = 1
then select #sql = #sql + ' innner join tableC'
if #usertableC != 1
then select #sql = #sql + ' innner join tableB
exec #sql
There is a good discussion of dynamic sql at "the curse and blessing of dynamic sql"
Nice solution, Geraldo! There is not be a performance hit on using the union. I can't tell you why (perhaps someone can fill in the gaps here), but the execution plan shows 0 I/O cost for the constant scan.
However, this does approach depend on the schemas for TableB and TableC being identical. To do this with multiple statements, supporting disparate schemas in TableB and TableC, I'd consider the following approach:
DECLARE #sql NVARCHAR(MAX)
SET #sql = 'SELECT td.* FROM TableA ta INNER JOIN Table' +
CASE WHEN #useTableC = 1 THEN 'C' ELSE 'B' END + ' td ON ta.ID = td.ID'
EXEC sp_executesql #sql
Note that it would then be up to your application code to determine the corresponding schema and read the data accordingly.