Optimization for system views - sql

I have a query for getting columns data from the Microsoft SQL Server database. I need to speed up my query because I will run it multiple times each minute. Currently, my query took about 60ms to execute on SQL Server. It would be awesome too cut it down to 30 or 40ms.
Execution plan: plan
Is there any possible way for optimization?
SELECT
c.name as 'columnName',
t.name as 'dataType',
t.name + '(' + cast(c.max_length as varchar(50)) +')' AS 'dataTypeFull',
ISNULL(sep.value,'') AS 'columnDescription',
CASE
WHEN fk.object_id is not null THEN fk.name ELSE NULL
END AS 'foreignKey',
pk_tab.*,
ISNULL(i.is_primary_key,0) AS 'primaryKey'
FROM
sys.tables tab
INNER JOIN
sys.columns c ON c.object_id = tab.object_id
LEFT OUTER JOIN
sys.index_columns ic ON ic.object_id = c.object_id AND ic.column_id = c.column_id
LEFT OUTER JOIN
sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
LEFT OUTER JOIN
sys.foreign_key_columns fk_cols ON fk_cols.parent_object_id = tab.object_id
AND fk_cols.parent_column_id = c.column_id
LEFT OUTER JOIN
sys.foreign_keys fk ON fk.object_id = fk_cols.constraint_object_id
LEFT OUTER JOIN
sys.tables pk_tab ON pk_tab.object_id = fk_cols.referenced_object_id
LEFT JOIN
sys.extended_properties sep ON c.object_id = sep.major_id
AND c.column_id = sep.minor_id
AND sep.name = 'MS_Description'
JOIN
sys.types t ON c.user_type_id = t.user_type_id
WHERE
c.object_id = Object_id('some-table-name')

Related

'ProductNumber'

I have a few questions I don't have any experience in a SQL, so my questions will looks funny to some experts here (-:
I want to run some checks in my production SQL.
I have a few databases and I want to check some things.
first, I want to check the index so I found this Query on this great website:
SELECT
t.name TableName,
col.name ColumnName,
ind.name IndexName
FROM
sys.indexes ind
INNER JOIN`enter code here`
sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id
INNER JOIN
sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id
INNER JOIN
sys.tables t ON ind.object_id = t.object_id
WHERE
(ind.is_primary_key = 0
AND t.is_ms_shipped = 0)
ORDER BY
t.name, col.name, ind.name
I don't know how to find t.name or col.name
I have found this Query that can find all the miss details
select * from information_schema.columns where column_name = 'ProductNumber'
But I dont know how to find the 'ProductNumber'
Last one, if I want to change the Snapshot Mode to ON it will ask to restart the server or it will have any impact on some running session or transaction and make any data corruption?
Use col.name like '%ProductNumber%' in where condition
SELECT
t.name TableName,
col.name ColumnName,
ind.name IndexName
FROM
sys.indexes ind
INNER JOIN`enter code here`
sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id
INNER JOIN
sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id
INNER JOIN
sys.tables t ON ind.object_id = t.object_id
WHERE
ind.is_primary_key = 0
AND t.is_ms_shipped = 0 and col.name like '%ProductNumber%'
ORDER BY
t.name, col.name, ind.name

Use CTE To Create Subset of Data

I'm wanting to create a subset of data for testing purposes, where I start with a Users table, select X of type a, Y of type b, Z of type c (and so on), and create a new table containing those users. I then need to to create all related tables (with the necessary records), and then all related tables to those...
I'm fairly certain the best way to do this is a recursive common table expression, however I don't have much experience with those and was hoping someone could help me out. So far I have the below, but have noticed two things:
Level 2 seems to contain everything that was in level 1, in addition to the new records I'd expect
This doesn't actually create/insert the records yet (I still need help with that)
WITH cte AS
(
SELECT DISTINCT fk.object_id, fk.schema_id, fk.parent_object_id, fc.parent_column_id, t.schema_id AS referenced_schema_id, fk.referenced_object_id, ic.column_id AS referenced_column_id, 1 AS Level
FROM sys.foreign_keys fk
INNER JOIN sys.tables t ON fk.referenced_object_id = t.object_id
INNER JOIN sys.foreign_key_columns fc ON fk.object_id = fc.constraint_object_id
INNER JOIN sys.indexes i ON fk.referenced_object_id = i.object_id AND i.is_primary_key = 1
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
WHERE fk.type = 'F'
AND fk.referenced_object_id = OBJECT_ID(N'dbo.Users', N'U')
UNION ALL
SELECT fk.object_id, fk.schema_id, fk.parent_object_id, fc.parent_column_id, t.schema_id, fk.referenced_object_id, ic.column_id AS referenced_column_id, cte.Level + 1
FROM sys.foreign_keys fk
INNER JOIN sys.tables t ON fk.referenced_object_id = t.object_id
INNER JOIN sys.foreign_key_columns fc ON fk.object_id = fc.constraint_object_id
INNER JOIN sys.indexes i ON fk.referenced_object_id = i.object_id AND i.is_primary_key = 1
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
INNER JOIN cte ON fk.referenced_object_id = cte.parent_object_id
WHERE fk.type = 'F'
AND fk.parent_object_id <> cte.referenced_object_id
),
cteHierarchy AS (
SELECT DISTINCT
OBJECT_NAME(cte.object_id) AS ReferringKey,
SCHEMA_NAME(cte.schema_id) AS ReferringSchema,
OBJECT_NAME(cte.parent_object_id) as ReferringTable,
COL_NAME(cte.parent_object_id,cte.parent_column_id) ReferringColumn,
SCHEMA_NAME(cte.referenced_schema_id) AS ReferencedSchema,
OBJECT_NAME(cte.referenced_object_id) as ReferencedTable,
COL_NAME(cte.referenced_object_id,cte.referenced_column_id) ReferencedColumn,
Level
FROM cte
)
SELECT *
FROM cteHierarchy
ORDER BY Level, ReferencedSchema, ReferencedTable, ReferringTable;
Thank you for your assistance!

Getting duplication with inner join and left join

I am trying to fetch following information for the table of the columns :
1) Primary key.
2) IsNullable
3) Is_Identity.
Query :
SELECT c.name 'Column Name',c.is_nullable,c.is_identity,ISNULL(i.is_primary_key, 0) 'Primary Key' FROM sys.columns c INNER JOIN sys.types t ON c.user_type_id = t.user_type_id LEFT OUTER JOIN sys.index_columns ic ON ic.object_id = c.object_id AND ic.column_id = c.column_id LEFT OUTER JOIN sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id WHERE c.object_id = OBJECT_ID('[HumanResources].[Employee]')
I am working with Adventure Works database but the problem here is I am getting OrganizationNode column 2 times and I am unable to understand the reason.
For other tables I am not getting this issue but I am only getting this problem for the table [HumanResources].[Employee].
Below is the link to download database bak file :
https://www.dropbox.com/s/nutfat17b73boav/AdvantureWorksSeScript.bak?dl=0
I have also tried distinct but because of that it shuffled up the ordering of the column as you can see in the second output. BirthDate is coming at the top instead of BusinessEntityID.
I would not like to use distinct as my below query is working fine with all other tables but I am not getting why it is giving duplicate columns in case of [HumanResources].[Employee] table or may be I have tested it with few tables and query may not work properly for few other databases.
I am not sure whether my query is correct or not to work in all the scenarios to fetch above 3 things(pk,inullable etc.) which I mention.
Try this
SELECT name,
is_identity,
is_nullable,
is_primary_key
FROM (
SELECT c.name,
c.column_id,
c.is_identity,
c.is_nullable,
ISNULL(i.is_primary_key,0) is_primary_key,
ROW_NUMBER() OVER(PARTITION BY c.name ORDER BY c.name) rn
FROM sys.columns c
JOIN sys.tables t
ON t.object_id = c.object_id
LEFT JOIN sys.index_columns ic
ON c.object_id = ic.object_id AND c.column_id = ic.column_id
LEFT JOIN sys.indexes i
ON i.object_id = ic.object_id AND i.index_id = ic.index_id
WHERE t.name = 'Employee'
)keys
WHERE rn = 1
ORDER BY column_id

List all foreign keys of a table, multiple foreign keys to same table

I use the following SQL to query a given table's keys (primary and foreign keys) and their descriptions. I am using SQL Server 2005.
SELECT c.name 'Column Name' ,
t.name 'Data type' ,
c.max_length 'Max Length' ,
c.precision ,
c.scale ,
c.is_nullable ,
ISNULL(i.is_primary_key, 0) 'Primary Key' ,
CAST (( SELECT COUNT(*)
FROM ( SELECT cx.object_id
FROM sys.foreign_key_columns fkc
INNER JOIN sys.columns cx ON fkc.parent_column_id = cx.column_id
AND fkc.parent_object_id = cx.object_id
INNER JOIN sys.columns cref ON fkc.referenced_column_id = cref.column_id
AND fkc.referenced_object_id = cref.object_id
WHERE cx.column_id = c.column_id
AND fkc.parent_object_id = OBJECT_ID('[dbo].Cards')
) xxx
) AS BIT) AS 'Foreign Key' ,
( SELECT OBJECT_SCHEMA_NAME(fkc.referenced_object_id)
FROM sys.foreign_key_columns fkc
INNER JOIN sys.columns cy ON fkc.parent_column_id = cy.column_id
AND fkc.parent_object_id = cy.object_id
INNER JOIN sys.columns cref ON fkc.referenced_column_id = cref.column_id
AND fkc.referenced_object_id = cref.object_id
WHERE cy.column_id = c.column_id
AND fkc.parent_object_id = OBJECT_ID('[dbo].Cards')
) 'Schema Name' ,
( SELECT OBJECT_NAME(referenced_object_id)
FROM sys.foreign_key_columns fkc
INNER JOIN sys.columns cy ON fkc.parent_column_id = cy.column_id
AND fkc.parent_object_id = cy.object_id
INNER JOIN sys.columns cref ON fkc.referenced_column_id = cref.column_id
AND fkc.referenced_object_id = cref.object_id
WHERE cy.column_id = c.column_id
AND fkc.parent_object_id = OBJECT_ID('[dbo].Cards')
) 'Referenced table' ,
( SELECT cref.name
FROM sys.foreign_key_columns fkc
INNER JOIN sys.columns cy ON fkc.parent_column_id = cy.column_id
AND fkc.parent_object_id = cy.object_id
INNER JOIN sys.columns cref ON fkc.referenced_column_id = cref.column_id
AND fkc.referenced_object_id = cref.object_id
WHERE cy.column_id = c.column_id
AND fkc.parent_object_id = OBJECT_ID('[dbo].Cards')
) 'Referenced column name' ,
( SELECT sep.value [Description]
FROM sys.extended_properties sep
WHERE OBJECT_ID('[dbo].Cards') = sep.major_id
AND c.column_id = sep.minor_id
) Description FROM sys.columns c
INNER JOIN sys.types t ON c.user_type_id = t.user_type_id
LEFT OUTER JOIN sys.index_columns ic ON ic.object_id = c.object_id
AND ic.column_id = c.column_id
LEFT OUTER JOIN sys.indexes i ON ic.object_id = i.object_id
AND ic.index_id = i.index_id WHERE c.object_id = OBJECT_ID('[dbo].Cards');
The query works very well for all tables, unless the table has two foreign keys to the same table.
The error I'm getting is,
"Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression."
What am I doing wrong?
I didn't check your second query but the problem is still there:
the subquery that returnes more than 1 value is this one
( SELECT sep.value [Description]
FROM sys.extended_properties sep
WHERE OBJECT_ID('person.stateProvince') = sep.major_id
AND c.column_id = sep.minor_id
) Description
you should add additional condition in the where clause:
and class = 1 -- OBJECT_OR_COLUMN
your query does not consider more than 1 indexes for table, joining on c.column_id = sep.minor_id you cat get more rows because when the class is 7 (index) minor_id is the index id, not the column id
I have solved my own problem.
Posting here in case anyone stumbles upon this question.
SELECT c.name 'Column Name' ,
t.name 'Data type' ,
c.max_length 'Max Length' ,
c.precision ,
c.scale ,
c.is_nullable ,
ISNULL(i.is_primary_key, 0) 'Primary Key' ,
CAST (( SELECT COUNT(*)
FROM ( SELECT cx.object_id
FROM sys.foreign_key_columns fkc
INNER JOIN sys.columns cx ON fkc.parent_column_id = cx.column_id
AND fkc.parent_object_id = cx.object_id
INNER JOIN sys.columns cref ON fkc.referenced_column_id = cref.column_id
AND fkc.referenced_object_id = cref.object_id
WHERE cx.column_id = c.column_id
AND fkc.parent_object_id = OBJECT_ID('[dbo].Cards')
) xxx
) AS BIT) AS 'Foreign Key' ,
( SELECT TOP 1 OBJECT_SCHEMA_NAME(fkc.referenced_object_id)
FROM sys.foreign_key_columns fkc
INNER JOIN sys.columns cy ON fkc.parent_column_id = cy.column_id
AND fkc.parent_object_id = cy.object_id
INNER JOIN sys.columns cref ON fkc.referenced_column_id = cref.column_id
AND fkc.referenced_object_id = cref.object_id
WHERE cy.column_id = c.column_id
AND fkc.parent_object_id = OBJECT_ID('[dbo].Cards')
) 'Schema Name' ,
( SELECT TOP 1 OBJECT_NAME(referenced_object_id)
FROM sys.foreign_key_columns fkc
INNER JOIN sys.columns cy ON fkc.parent_column_id = cy.column_id
AND fkc.parent_object_id = cy.object_id
INNER JOIN sys.columns cref ON fkc.referenced_column_id = cref.column_id
AND fkc.referenced_object_id = cref.object_id
WHERE cy.column_id = c.column_id
AND fkc.parent_object_id = OBJECT_ID('[dbo].Cards')
) 'Referenced table' ,
( SELECT TOP 1 cref.name
FROM sys.foreign_key_columns fkc
INNER JOIN sys.columns cy ON fkc.parent_column_id = cy.column_id
AND fkc.parent_object_id = cy.object_id
INNER JOIN sys.columns cref ON fkc.referenced_column_id = cref.column_id
AND fkc.referenced_object_id = cref.object_id
WHERE cy.column_id = c.column_id
AND fkc.parent_object_id = OBJECT_ID('[dbo].Cards')
) 'Referenced column name' ,
( SELECT sep.value [Description]
FROM sys.extended_properties sep
WHERE OBJECT_ID('[dbo].Cards') = sep.major_id
AND c.column_id = sep.minor_id
) Description FROM sys.columns c
INNER JOIN sys.types t ON c.user_type_id = t.user_type_id
LEFT OUTER JOIN sys.index_columns ic ON ic.object_id = c.object_id
AND ic.column_id = c.column_id
LEFT OUTER JOIN sys.indexes i ON ic.object_id = i.object_id
AND ic.index_id = i.index_id WHERE c.object_id = OBJECT_ID('[dbo].Cards');

Identifying all columns included in composite PK throughout the database

I want to identify all the columns which are part of PK (composite or non-composite) throughout all the tables in my database. How can I do that with a sql statement? Desired result set:
TABLE NAME | COLUMN NAME | DATA TYPE | CONSTRAINT |
in Sql Server exists a system view to show all constraints.
Try this:
select * from sys.key_constraints where type_desc = 'PRIMARY_KEY_CONSTRAINT'
Something like this:
select
t.name as [TABLE NAME],
c.name as [COLUMN NAME],
ty.name as [DATA TYPE],
i.name as [CONSTRAINT]
from sys.index_columns ic
join sys.indexes i
on ic.object_id = i.object_id
and ic.index_id = i.index_id
join sys.columns c
on ic.object_id = c.object_id
and ic.column_id = c.column_id
join sys.tables t
on ic.object_id = t.object_id
join sys.types ty
on c.user_type_id = ty.user_type_id
where i.is_primary_key = 1
I copied this into my snippets folder long ago, so I can't take credit for it, but this works well...
select s.name as TABLE_SCHEMA, t.name as TABLE_NAME, k.name as CONSTRAINT_NAME, c.name as COLUMN_NAME, ic.key_ordinal AS ORDINAL_POSITION
from sys.key_constraints as k
join sys.tables as t
on t.object_id = k.parent_object_id
join sys.schemas as s
on s.schema_id = t.schema_id
join sys.index_columns as ic
on ic.object_id = t.object_id
and ic.index_id = k.unique_index_id
join sys.columns as c
on c.object_id = t.object_id
and c.column_id = ic.column_id
where k.type = 'PK';
SELECT o.name AS TableName, c.Name AS ColumnName, t.name AS DataType, kc.name AS ContraintName
FROM sys.key_constraints kc
INNER JOIN sys.index_columns ic ON kc.parent_object_id = ic.object_id AND kc.unique_index_id = ic.index_id
INNER JOIN sys.columns c ON ic.column_id = c.column_id AND c.object_id = ic.object_id
INNER JOIN sys.objects o ON ic.object_id = o.object_id
INNER JOIN sys.types t ON c.system_type_id = t.system_type_id AND c.user_type_id = t.user_type_id
WHERE kc.type = 'PK'
ORDER BY TableName,ic.key_ordinal