with XMLNAMESPACES ('http://schemas.microsoft.com/sqlserver/2004/07/showplan' as sql)

SELECT * FROM

 (

 SELECT

  db_name(qt.dbid) AS 'DB Name'

  ,qt.dbid

  ,OBJECT_NAME(qp.objectid,qp.dbid) as sp_name

  ,qt.text AS 'sp_text'

  , substring(qt.text, (qs.statement_start_offset/2)+1

   , ((case qs.statement_end_offset

      when -1 then datalength(qt.text)

      else qs.statement_end_offset

      end - qs.statement_start_offset)/2) + 1) as statement_text

  , qs.creation_time

  , qs.execution_count AS 'Execution Count'

  , ISNULL(qs.execution_count/DATEDIFF(Second, qs.creation_time, GetDate()), 0) AS 'Calls/Second'

  , DATEDIFF(Minute, qs.creation_time, GetDate()) AS 'Age in Cache'

  , ISNULL(qs.total_elapsed_time/qs.execution_count, 0) AS 'AvgElapsedTime(㎲)'

  , qs.total_elapsed_time/1000.0/1000.0 AS 'TotalElapsedTime(sec)'

  , max_elapsed_time /1000.0 AS 'maxelapsedTime(ms)'

  , qs.total_worker_time/qs.execution_count AS 'AvgWorkerTime(㎲)'

  , qs.total_worker_time AS 'TotalWorkerTime(㎲)'

  , max_worker_time as 'max_worker_time(㎲)'

  , ISNULL(qs.total_logical_reads/qs.execution_count, 0) AS 'AvgLogicalreads'

  , total_logical_reads

  , qs.max_logical_reads

  , ISNULL(qs.total_physical_reads/qs.execution_count, 0) AS 'AvgphysicalReads'

  , total_physical_reads

  , qs.max_physical_reads

  , ISNULL(qs.total_logical_writes/qs.execution_count, 0) AS 'AvglogicalWrites'

  , qs.total_logical_writes

  , qs.max_logical_writes

  ,text

  ,cast(query_plan as xml) as query_plan

 FROM sys.dm_exec_query_stats as qs

 CROSS APPLY sys.dm_exec_sql_text(plan_handle) as qt

 CROSS APPLY sys.dm_exec_text_query_plan(qs.plan_handle,qs.statement_start_offset,qs.statement_end_offset) qp

 WHERE  db_name(qt.dbid) <> 'nxdba'

)Y

CROSS APPLY

(

      SELECT

       c.value('(./@PhysicalOp)[1]','varchar(100)') as PhysicalOp

       FROM Y.query_plan.nodes('//sql:RelOp')B(C)

)X

where PhysicalOp  IN ('Table Scan','Index Scan')and

Y.dbid not in (1,2,3,4,32767)

'Database > Query' 카테고리의 다른 글

sp_who3  (0) 2020.08.29
특정 문자열 포함하는 프로시저  (0) 2020.08.28
모든 인덱스 다시 리빌드, 통계 업데이트  (0) 2020.08.28
INDEX 사용량  (0) 2020.08.28
INDEX 정보  (0) 2020.08.28
/* =====================================================================================================

모든 인덱스 다시 리빌드

======================================================================================================*/

DECLARE @i int, @sql varchar(1000)
DECLARE @tablename varchar(1000),@ownerName  varchar(1000)

SET @i = 1

DECLARE DB_Cursor CURSOR FOR
SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES  WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_SCHEMA, TABLE_NAME

OPEN DB_Cursor

FETCH NEXT FROM DB_Cursor
INTO @ownerName, @tablename
WHILE @@FETCH_STATUS = 0
BEGIN

SET @sql = 'ALTER INDEX ALL ON ' + @ownerName + '.' + @tablename + ' REBUILD WITH (PAD_INDEX = ON, FILLFACTOR = 90) '

EXEC (@sql)

PRINT CONVERT(VARCHAR, @i) + '__' + @ownerName + '.' + @tablename + '............ OK'

SET @i = @i + 1

 FETCH NEXT FROM DB_Cursor

INTO @ownerName, @tablename

 END

CLOSE DB_Cursor

DEALLOCATE DB_Cursor


/* =====================================================================================================

데이터베이스의 모든 통계 업데이트

======================================================================================================*/

SP_UPDATESTATS

'Database > Query' 카테고리의 다른 글

특정 문자열 포함하는 프로시저  (0) 2020.08.28
Full Scan, Index Scan Query  (0) 2020.08.28
INDEX 사용량  (0) 2020.08.28
INDEX 정보  (0) 2020.08.28
동적 쿼리2  (0) 2020.08.27
select object_name( idx.object_id) as 'table',
	idx.name as 'index',
	idx.index_id as 'id',
	idx.type_desc as 'type',
	icol.column_id,
	usg.user_seeks,
	usg.last_user_seek,
	usg.user_scans,
	usg.last_user_scan,
	usg.user_lookups,
	usg.last_user_lookup
from sys.indexes idx inner join sys.dm_db_index_usage_stats usg
	on usg.object_id = idx.object_id and idx.index_id = usg.index_id and usg.database_id = db_id()
	left join sys.index_columns icol on icol.index_id = usg.index_id and icol.object_id = idx.object_id
and usg.index_id IS null
and idx.type_desc not in ('heap','clustered')

 

'Database > Query' 카테고리의 다른 글

Full Scan, Index Scan Query  (0) 2020.08.28
모든 인덱스 다시 리빌드, 통계 업데이트  (0) 2020.08.28
INDEX 정보  (0) 2020.08.28
동적 쿼리2  (0) 2020.08.27
누락된 인덱스 정보 확인  (0) 2020.08.27
declare @SchemaName sysname=NULL

, @TableName sysname=NULL

, @IndexName sysname=NULL

, @dataspace sysname=NULL

 

set @SchemaName = 'schema'

set @TableName = 'table_name'

--set @IndexName = 'AK_SalesOrderDetail_rowguid'

 

 

declare @_SchemaName varchar(100)

declare @_TableName varchar(256)

declare @_IndexName varchar(256)

declare @ColumnName varchar(256)

declare @is_unique varchar(100)

declare @IndexTypeDesc varchar(100)

declare @FileGroupName varchar(100)

declare @is_disabled varchar(100)

declare @IndexColumnId int

declare @IsDescendingKey int

declare @IsIncludedColumn int

 

 

-- getting the index sizes

SELECT schema_name(t.schema_id) [SchemaName],

OBJECT_NAME(ix.OBJECT_ID) AS TableName,

ix.name AS IndexName,

CAST( 8 * SUM(a.used_pages)/1024.0 AS DECIMAL(20,1))AS 'Indexsize(MB)'

INTO #IndexSizeTable

from sys.tables t

inner join sys.indexes ix on t.object_id=ix.object_id

inner join sys.partitions AS p ON p.OBJECT_ID = ix.OBJECT_ID AND p.index_id = ix.index_id

inner join sys.allocation_units AS a ON a.container_id = p.partition_id

WHERE ix.type>0 and t.is_ms_shipped=0

and schema_name(t.schema_id)= isnull(@SchemaName,schema_name(t.schema_id)) and t.name=isnull(@TableName,t.name) AND ix.name=isnull(@IndexName, ix.name)

GROUP BY schema_name(t.schema_id), ix.OBJECT_ID,ix.name

ORDER BY OBJECT_NAME(ix.OBJECT_ID),ix.name

 

--getting important properties of indexes

select schema_name(t.schema_id) [SchemaName], t.name TableName, ix.name IndexName,

cast( '' as varchar(max)) AS IndexKeys, casT('' as varchar(max)) AS IncludedColumns,

ix.is_unique

, ix.type_desc, ix.fill_factor as [Fill_Factor]

, ix.is_disabled , da.name as data_space,

ix.is_padded,

ix.allow_page_locks,

ix.allow_row_locks,

INDEXPROPERTY(t.object_id, ix.name, 'IsAutoStatistics') IsAutoStatistics ,

ix.ignore_dup_key

INTO #helpindex

from sys.tables t

inner join sys.indexes ix on t.object_id=ix.object_id

inner join sys.data_spaces da on da.data_space_id= ix.data_space_id

where ix.type>0 and t.is_ms_shipped=0

and schema_name(t.schema_id)= isnull(@SchemaName,schema_name(t.schema_id)) and t.name=isnull(@TableName,t.name) AND ix.name=isnull(@IndexName, ix.name)

and da.name=isnull(@dataspace,da.name)

order by schema_name(t.schema_id), t.name, ix.name

 

---getting the index keys and included columns

declare CursorIndex cursor for

select schema_name(t.schema_id) [schema_name], t.name, ix.name

from sys.tables t

inner join sys.indexes ix on t.object_id=ix.object_id

where ix.type>0 and t.is_ms_shipped=0

and schema_name(t.schema_id)= isnull(@SchemaName,schema_name(t.schema_id)) and t.name=isnull(@TableName,t.name) AND ix.name=isnull(@IndexName, ix.name)

order by schema_name(t.schema_id), t.name, ix.name

open CursorIndex

fetch next from CursorIndex into @_SchemaName, @_TableName, @_IndexName

while (@@fetch_status=0)

begin

declare @IndexColumns varchar(4000)

declare @IncludedColumns varchar(4000)

set @IndexColumns=''

set @IncludedColumns=''

declare CursorIndexColumn cursor for

select col.name, ixc.is_descending_key, ixc.is_included_column

from sys.tables tb

inner join sys.indexes ix on tb.object_id=ix.object_id

inner join sys.index_columns ixc on ix.object_id=ixc.object_id and ix.index_id= ixc.index_id

inner join sys.columns col on ixc.object_id =col.object_id and ixc.column_id=col.column_id

where ix.type>0 and tb.is_ms_shipped=0

and schema_name(tb.schema_id)=@_SchemaName and tb.name=@_TableName and ix.name=@_IndexName

order by ixc.index_column_id

 

open CursorIndexColumn

fetch next from CursorIndexColumn into @ColumnName, @IsDescendingKey, @IsIncludedColumn

while (@@fetch_status=0)

begin

if @IsIncludedColumn=0

set @IndexColumns=@IndexColumns + @ColumnName +', '

else

set @IncludedColumns=@IncludedColumns + @ColumnName +', '

 

fetch next from CursorIndexColumn into @ColumnName, @IsDescendingKey, @IsIncludedColumn

end

close CursorIndexColumn

deallocate CursorIndexColumn

 

set @IndexColumns = substring(@IndexColumns, 1, len(@IndexColumns)-1)

set @IncludedColumns = case when len(@IncludedColumns) >0 then substring(@IncludedColumns, 1, len(@IncludedColumns)-1) else '' end

 

UPDATE #helpindex

SET IndexKeys = @IndexColumns, IncludedColumns=@IncludedColumns

WHERE [SchemaName]=@_SchemaName and TableName=@_TableName and IndexName=@_IndexName

 

fetch next from CursorIndex into @_SchemaName, @_TableName, @_IndexName

 

end

close CursorIndex

deallocate CursorIndex

 

--showing the results

SELECT hi.SchemaName, hi.TableName, hi.IndexName, hi.IndexKeys, hi.IncludedColumns, ixs.[Indexsize(MB)],

hi.is_unique, hi.type_desc,hi.data_space, hi.Fill_Factor, hi.IsAutoStatistics,

hi.is_disabled, hi.is_padded, hi.allow_page_locks, hi.allow_row_locks,hi.ignore_dup_key

FROM #helpindex hi

INNER JOIN #IndexSizeTable ixs ON hi.SchemaName=ixs.SchemaName and hi.TableName=ixs.TableName and hi.IndexName=ixs.IndexName

order by hi.IndexName

 

drop table #helpindex

drop table #IndexSizeTableix.name

'Database > Query' 카테고리의 다른 글

모든 인덱스 다시 리빌드, 통계 업데이트  (0) 2020.08.28
INDEX 사용량  (0) 2020.08.28
동적 쿼리2  (0) 2020.08.27
누락된 인덱스 정보 확인  (0) 2020.08.27
동적쿼리  (0) 2020.08.27

Visual Basic, ASP, VB.NET에서 ADO, ADO.NET을 이용한 Database 프로그램을 개발하는 경우 프로그램내에 SQL 구문을 문자열로 연결한 후 실행하도록 구성한 코드를 많이 보게 된다.

 

 

이러한 코드 구성을 일반적으로 '동적 쿼리', '하드 코딩된 쿼리'라 부른다.

 

 

예를 들어 비주얼 베이직의 경우

 

 

Dim strSQL As String

 

 

strSQL="select orderid, orderdate, employeeid from orders"

 

strSQL=strSQL+" where orderid=" & txtOrderID

 

 

cnn.Execute strSQL

 

 

하지만 이같은 동적 쿼리는 가능한 사용하지 않는 것이 좋다. 대신 SQL Server의 저장 프로시저를 이용해 처리 용량과 응답 속도의 향상 및 유지 보수 등 저장 프로시저의 특징을 활용하는 것이 좋다.

 

 

하지만 설계상의 문제나 또는 고객의 다양한 요구 구현 방법상의 이질적 문제로 인해 동적 쿼리를 써야하는 상황이 자주 발생한다. Q/A의 질문 유형 중에도 이같은 동적 쿼리 작성법에 관한 내용이 상당수를 차지하고 있다.

 

 

저장 프로시저를 통해 코드를 구성하더라도 저장 프로시저 내에서 다시 동적 쿼리를 사용하게 되는 경우가 발생한다. 온라인 설명서에는 이를 '런타임 시 명령문 작성'이라는 주제로 설명했다. 이 경우 SQL Server에서는 sp_executesql, exec()의 두가지 명령을 사용할 수 있다.

 

 

클라이언트나 서버 사이드에서 동적 쿼리를 사용해야 하는 상황이 되었을 때, 다시말해 저장 프로시저를 직접 사용할 수 없는 상황에서는 또 다른 해결 방법을 이용할 수 있다.

 

아래 두 가지 상황에서의 해결 방법이다.

 

 

클라인트 사이드에서 동적 쿼리가 필요한 경우

 

 

ADO, ADO.NET에서는 파라미터를 가진 동적 쿼리를 지정할 수 있으며 일반적으로 아래와 코드 구성을 가진다.

 

 

1. ADO, ODBC, Command 오브젝트 연동

 

Dim strSQL As String

 

 

strSQL="select orderid, orderdate, employeeid from orders"

 

strSQL=strSQL+" where orderid = ?"

 

 

2. ADO.NET, SqlClient 네임스페이스, SqlCommand 오브젝트와 연동

 

Dim strSQL As String

 

 

strSQL="select orderid, orderdate, employeeid from orders"

 

strSQL=strSQL+" where orderid = @orderid"

 

 

위에 코드를 실행하면 실제 SQL Server에서는 sp_executesql 시스템 프로시저를 통해서 실행이 된다. 특히 ADO.NET의 경우는 디자인 타임에 'SqlDataAdapter Configuration Wizard'를 사용하면 위와 같은 코드를 작성해 준다.

 

 

SQL Server, 저장 프로시저에서 동적 쿼리가 필요한 경우

 

exec() 아니라 sp_executesql 시스템 프로시저를 이용한다.

 

 

결국 클라이언트 사이드건 서버 사이드건 sp_executesql이 사용된 것을 알 수 있다. exec()를 쓴 경우와 sp_executesql를 사용한 경우의 성능과 SQL Server의 Cache 매니저의 상황 비교에 대한 내용을 마지막에 추가해 두었다.

 

 

일반적으로 sp_executesql은 exec()비해 몇 가지 장점을 제공한다.

 

 

1. 쿼리문안에 매개변수(입력/출력)를 정의할 수 있다.

 

2. 매개변수 사용으로 인해 쿼리 최적화 프로그램이 컴파일된 실행 플랜을 재 사용할 확률이 높아진다.

 

 

실제로 exec()와 sp_executesql은 Cache 매니저의 처리 방법 및 활동 상태가 다르다는 것을 마지막에 추가한 성능 모니터링을 통해서 알 수가 있을 것이다.

 

 

이번 기회의 sp_executesql 시스템 프로시저 다양한 사용법과 관련 지식을 얻는데 미력하나마 도움이 됐으면 한다. 그럼, 구문부터 살펴보자.

 

 

sp_executesql [@stmt =] stmt

 

[

 

{, [@params =] N'@parameter_name data_type [,...n]' }

 

{, [@param1 =] 'value1' [,...n] }

 

]

 

 

인수설명

 

@stmt: T-SQL문 또는 배치 명령. ntext 형으로 변환될 수 있는 변수 또는 유니코드 상수 문자열. 내부에 @name 형식의 파라미터를 포함할 수 있다.

 

@params: @stmt에 포함된 모든 파라미터의 이름과 데이터 타입을 정의한다.

 

@param1: @params 파라미터에서 첫번째 파라미터에 할당할 값

 

n : 각 파라미터에 대한 값을 할당한다.

 

 

참고

 

UNICODE 문자열 상수를 지정할 때는 N'...'형식을 사용한다.sp_executesql 프로시저에 선언됐던 파라미터가 ntext형이기 때문에 문자열을 직접 지정할 때는 위와 같은 형태를 사용하면 된다.

 

 

sp_executesql은 sql로 구성된 시스템 프로시저가 아니라 확장 프로시저이다.

 

 

기본 예제

 

1. TOP 절의 값을 동적으로 지정하고자 하는 경우(아래 구문은 set rowcount n 세션 옵션으로 대치할 수도 있다)

 

 

declare @cnt as nvarchar(5)



declare @stmt as nvarchar(100)



set @cnt = '5'



set @stmt = 'select top ' + @cnt + ' * from northwind.dbo.orders'





exec sp_executesql @stmt





아래 예제는 단순히 SQL을 동적으로 작성하고자 하는 경우로 @db의 값이 실행 시마다



다른 데이터베이스명이 올 수 있다고 가정한다. 테이블명은 동일한다.





declare @db as nvarchar(20)



declare @stmt as nvarchar(100)



set @db = 'northwind'



set @stmt = 'select * from '+ @db +'.dbo.orders'





exec sp_executesql @stmt

 

 

2. 하나 이상의 명령을 배치로 실행

 

 

declare @stmt as nvarchar(500)



set @stmt = 'use northwind; '



set @stmt = @stmt + 'select top 5 * from dbo.orders where



orderid=10248; '



set @stmt = @stmt + 'select top 5 * from dbo.[order details] where



orderid=10248'





exec sp_executesql @stmt

 

 

입력 파라미터를 적용한 예제

 

 

1. @orderid 입력 파라미터를 이용해 해당 주문 번호를 가진 [order details] 테이블의 주문 제품 정보를 출력

 

 

use northwind





declare @stmt as nvarchar(100)



declare @params as nvarchar(100)



set @stmt = 'select productid, quantity, unitprice from '



set @stmt = @stmt + 'dbo.[order details] where orderid=@orderid'



set @params = '@orderid int'





exec sp_executesql @stmt, @params, @orderid=10248

 

 

2. 위 예제를 저장 프로시저 안에서 연동한 경우

 

 

use northwind





create proc upOrderDetailsSel



@porderid int



as



declare @stmt as nvarchar(100)



declare @params as nvarchar(100)



set @stmt = 'select productid, quantity, unitprice from '



set @stmt = @stmt + 'dbo.[order details] where orderid=@orderid'



set @params = '@orderid int'





exec sp_executesql @stmt, @params, @orderid=@porderid



go



exec upOrderDetailsSel @porderid = 10248

 

 

input 파라미터를 적용한 예제

 

 

1. @table을 입력 파라미터를 이용해서 실제 입력할 대상 테이블을 결정 입력될 컬럼값들 또한 입력 파라미터로 처리한 예제

 

 

-- 아래 테스트용 테이블을 우선 작성할 것.



create table northwind.dbo.table1 (a int, b int, c int)





use northwind





declare @table as nvarchar(20)



declare @stmt as nvarchar(100)



declare @params as nvarchar(100)





set @table = 'dbo.table1'



set @stmt = 'insert into ' + @table + ' '



set @stmt = @stmt + 'values (@a, @b, @c)'



set @params = '@a int, @b int, @c int'





exec sp_executesql @stmt, @params, @a=1, @b=2, @c=3





확인





select * from table1

 

 

2 .output 파라미터를 적용한 예제

 

 

동적 SQL문 내에도 출력(OUTPUT) 파라미터를 선언하고 결과 값을 리턴 받을 수 있다. 저장 프로시저에서 출력 파라미터를 사용하는 것과 동일하게, 선언부와 호출부에 반드시 OUTPUT 키워드를 지정한다.

 

 

use northwind





declare @stmt as nvarchar(100)



declare @params as nvarchar(100)



declare @orderret as int





set @stmt = 'select @ordercnt = count(*) from dbo.orders'



set @params = '@ordercnt as int OUTPUT' -- OUTPUT 키워드에 주의





여기도 OUTPUT 키워드를 지정한다.





exec sp_executesql @stmt, @params, @ordercnt = @orderret OUTPUT





확인





select @orderret

 

 

지원이 안되는 것들은 다음과 같다

 

 

*. sp_executesql은 배치, 저장 프로시저, 트리거처럼 한 배치로 실행된다.

 

 

1.동적 SQL문에서는 RETURN 문을 사용할 수 없다

 

 

2.로컬 변수를 액세스 할 수 없다

 

 

declare @chr char(3)



set @chr = 'abc'





sp_executesql N'PRINT @CharVariable'



GO

 

 

3. 현재 데이터베이스가 변경되지 않는다

 

use pubs



go



sp_executesql N'use northwind'



select * from shippers -- shippers 테이블은 northwind에 있다.



go

 

 

전문 개발자및 관리자를 위한 추가 정보

 

 

성능 비교

 

만일, 여러분이 Windows NT/2000의 성능 모니터의 사용법을 알고 있다면 아래 3가지 사용 예에 대한 모니터를 수행하고 각각 Cache Manager상의 활동이 어떻게 다른지를 비교 해 보면 많은 도움이 될 것이다.

 

 

아래에 성능 모니터에 모니터링할 관련 오브젝트 및 카운트을 적어 뒀다.

 

 

성능 개체

 

SQL Server:Cache Manager

 

- 모든 카운터

 

- 다음 목록에서 인스턴스 선택

 

_Total

 

Adhoc Sql Plans

 

Execution Context

 

Procedure Plans

 

기타... (관심이 있다면)

 

 

참고

 

3개의 방법을 개별적으로 테스트할 때, Procedure Cache상에 동일한 플랜이 재 사용되는 것을 방지하기 위해

 

 

DBCC FREEPROCCACHE

 

 

명령을 사용할 수 있다. 이 명령은 프로시저 캐시에서 모든 요소를 제거한다. 이 작업을 수행해야 Cache Object Counter가 늘어나는 것을 볼 수 있다. 그리고 현재 Cache된 Object에 대한 정보를 보고자 하는 경우 아래의 쿼리를 이용하면 된다.

 

 

select * from master..syscacheobjects



where dbid = db_id('northwind')

 

 

1. 저장 프로시저 테스트용

 

DROP PROC dbo.upOrderDetailsQuery



CREATE PROC dbo.upOrderDetailsQuery



@orderid int



AS



select productid, quantity, unitprice from dbo.[order details]



where orderid = @orderid



go



EXEC dbo.upOrderDetailsQuery @orderid = 10248

 

 

2. sp_executesql

 

 

USE Northwind





declare @stmt as nvarchar(100)



declare @params as nvarchar(100)



set @stmt = 'select productid, quantity, unitprice from '



set @stmt = @stmt + 'dbo.[order details] where orderid=@orderid'



set @params = '@orderid int'





exec sp_executesql @stmt, @params, @orderid=10248



go

 

 

3. EXEC() 사용

 

 

USE Northwind





declare @stmt as nvarchar(100)



declare @orderid varchar(10)



set @orderid = '10248'



set @stmt = 'select productid, quantity, unitprice from '



set @stmt = @stmt + 'dbo.[order details] where orderid = '+ @orderid





EXEC (@stmt) 

'Database > Query' 카테고리의 다른 글

INDEX 사용량  (0) 2020.08.28
INDEX 정보  (0) 2020.08.28
누락된 인덱스 정보 확인  (0) 2020.08.27
동적쿼리  (0) 2020.08.27
SQL Server 요일  (0) 2020.08.27

-- 누락된 인덱스 확인 쿼리

SELECT  TOP 30

        [Index Advantage] = ROUND(avg_total_user_cost * avg_user_impact * (user_seeks + user_scans),0) 

        , avg_user_impact

        , TableName = statement

        , [EqualityUsage] = equality_columns 

        , [InequalityUsage] = inequality_columns

        , [Include Cloumns] = included_columns

        , [Unique Compiles] = unique_compiles

        , user_seeks

FROM        sys.dm_db_missing_index_groups g WITH (NOLOCK)

INNER JOIN    sys.dm_db_missing_index_group_stats s WITH (NOLOCK)

       ON s.group_handle = g.index_group_handle 

INNER JOIN    sys.dm_db_missing_index_details d WITH (NOLOCK)

       ON d.index_handle = g.index_handle

ORDER BY [Index Advantage] DESC;



equality_columns : WHERE절에 같음(=) 조건으로 사용되는 컬럼

inequality_columns : WHERE절에 같지 않은(<,>) 조건으로 사용되는 컬럼

included_columns : SELECT 절에 나오는 컬럼

 

 

쿼리의 컬럼 설명

 

sys.dm_db_missing_index_group_stats

 

열 이름데이터 형식설명

group_handle

int

누락된 인덱스 그룹을 식별합니다. 이 식별자는 서버에서 고유합니다.

다른 열은 그룹의 인덱스가 누락된 것으로 간주되는 모든 쿼리에 대한 정보를 제공합니다.

인덱스 그룹에는 인덱스가 하나만 포함되어 있습니다.

unique_compiles

bigint

이 누락된 인덱스 그룹에 적합한 컴파일 및 다시 컴파일 수입니다. 서로 다른 많은 쿼리의 컴파일 및 다시 컴파일이 이 열 값에 영향을 줄 수 있습니다.

user_seeks

bigint

그룹의 권장 인덱스가 사용되었을 수 있는 사용자 쿼리에 의해 수행된 검색(Seek) 수입니다.

user_scans

bigint

그룹의 권장 인덱스가 사용되었을 수 있는 사용자 쿼리에 의해 수행된 검색(Scan) 수입니다.

last_user_seek

datetime

그룹의 권장 인덱스가 사용되었을 수 있는 사용자 쿼리에 의해 수행된 마지막 검색(Seek)의 날짜와 시간입니다.

last_user_scan

datetime

그룹의 권장 인덱스가 사용되었을 수 있는 사용자 쿼리에 의해 수행된 마지막 검색(Scan)의 날짜와 시간입니다.

avg_total_user_cost

float

그룹의 인덱스로 줄일 수 있는 사용자 쿼리의 평균 비용입니다.

avg_user_impact

float

누락된 인덱스 그룹을 구현할 경우 사용자 쿼리에서 얻을 수 있는 적합한 평균 백분율입니다. 즉, 이 누락된 인덱스 그룹을 구현할 경우 쿼리 비용이 평균적으로 이 백분율만큼 감소합니다.

system_seeks

bigint

그룹의 권장 인덱스가 사용되었을 수 있는 auto stats 쿼리와 같은 시스템 쿼리에 의해 수행된 검색(Seek) 수입니다. 자세한 내용은 Auto Stats 이벤트 클래스를 참조하십시오.

system_scans

bigint

그룹의 권장 인덱스가 사용되었을 수 있는 시스템 쿼리에 의해 수행된 검색(Scan) 수입니다.

last_system_seek

datetime

그룹의 권장 인덱스가 사용되었을 수 있는 시스템 쿼리에 의해 수행된 마지막 시스템 검색(Seek)의 날짜와 시간입니다.

last_system_scan

datetime

그룹의 권장 인덱스가 사용되었을 수 있는 시스템 쿼리에 의해 수행된 마지막 시스템 검색(Scan)의 날짜와 시간입니다.

avg_total_system_cost

float

그룹의 인덱스로 줄일 수 있는 시스템 쿼리의 평균 비용입니다.

avg_system_impact

float

누락된 인덱스 그룹을 구현할 경우 시스템 쿼리에서 얻을 수 있는 적합한 평균 백분율입니다. 즉, 이 누락된 인덱스 그룹을 구현할 경우 쿼리 비용이 평균적으로 이 백분율만큼 감소합니다.

 

sys.dm_db_missing_index_details

열 이름데이터 형식설명

index_handle

int

특정 누락된 인덱스를 식별합니다. 이 식별자는 서버에서 고유합니다. index_handle은 이 테이블의 키입니다.

database_id

smallint

누락된 인덱스가 있는 테이블이 위치한 데이터베이스를 식별합니다.

object_id

int

인덱스가 없는 테이블을 식별합니다.

equality_columns

nvarchar(4000)

다음 형식의 같음 조건자에 적용되는 쉼표로 구분된 열 목록입니다.

table.column =constant_value

inequality_columns

nvarchar(4000)

다음 형식의 같지 않음 조건자에 적용되는 쉼표로 구분된 열 목록입니다.

table.column > constant_value

"="가 아닌 모든 비교 연산자는 같지 않음을 표시합니다. 전체 비교 연산자 목록은 비교 연산자(데이터베이스 엔진)를 참조하십시오.

included_columns

nvarchar(4000)

쿼리에 대한 포함 열로서 필요한 쉼표로 구분된 열 목록입니다. 포함 열 또는 포괄 열에 대한 자세한 내용은 포괄 열을 사용하여 인덱스 만들기를 참조하십시오.

statement

nvarchar(4000)

인덱스가 없는 테이블의 이름입니다.

 

'Database > Query' 카테고리의 다른 글

INDEX 정보  (0) 2020.08.28
동적 쿼리2  (0) 2020.08.27
동적쿼리  (0) 2020.08.27
SQL Server 요일  (0) 2020.08.27
INDEX 인덱스 모니터링  (0) 2020.08.27

정적쿼리만 하다가 동적쿼리를 하면 조금 복잡하고 어려울 수 있다.

그러면 왜 동적쿼리를 사용해야 되냐?

그 이유는 예외처리를 위해 WHERE 절에 들어가야는 조건절을 손쉽게 제어하기 위함이다.

천천히 따라해보자.

 

예제

테이블 생성

CREATE TABLE #MEMBER(

  num      INT,

  name    NVARCHAR(20),

    score    INT

)

INSERT INTO #MEMBER (num, name, score) VALUES(1, '홍길동', 90);

INSERT INTO #MEMBER (num, name, score) VALUES(2, '고길동', 85);

INSERT INTO #MEMBER (num, name, score) VALUES(3, '피카츄', 83);

INSERT INTO #MEMBER (num, name, score) VALUES(4, '파이리', 85);

INSERT INTO #MEMBER (num, name, score) VALUES(5, '꼬북이', 80);

 

 

테이블 예제

 

동적쿼리 생성 과정

-- 매개 변수들을 선언해준다.

DECLARE @sql    AS NVARCHAR(MAX),  -- SQL 구문

        @sqlp    AS NVARCHAR(MAX),  -- SQL 매개 변수

        @num    AS INT,            -- num 매개 변수

        @name    AS NVARCHAR(20),    -- name 매개 변수

        @score  AS INT              -- score 매개 변수



-- WHERE 절에 들어갈 변수

SET @score = 85;



-- 기본적인 SELECT 구문

SET @sql = N'SELECT * FROM #MEMBER WHERE 1=1 ';



-- IF 절로 예외처리

IF ISNULL(@num, 0) > 0 BEGIN

    SET @sql = @sql + ' AND num = @num ';

END

IF ISNULL(@name, '') != '' BEGIN

    SET @sql = @sql + N' AND name = ''' + @name + N'''';

END

IF ISNULL(@score, 0) > 0 BEGIN

    SET @sql = @sql + ' AND score = @score';

END



-- EXECUTESQL에 들어갈 매개변수 정의

SET @sqlp = N'

    @num    AS INT,

    @name    AS NVARCHAR(20),

    @score  AS INT';



-- 실행

EXEC SP_EXECUTESQL @sql, @sqlp, @num=@num, @name=@name, @score=@score;

 

 

 

 

 

Input Parameter 값의 유무에 따라서 WHERE 조건절에 들어갈지 말아야할지 정할때 동적쿼리를 가장 많이 사용한다.

@num/@name/@score 값의 유무를 @sql에 넣어준다.

 

 

@sql 변수에 들어간 동적쿼리

 

@sql 변수의 값이 자유자재로 변하게 된다.

 

원하는 결과값이 출력

 

정리

이전 회사에서 동적쿼리가 좋은지?

정적쿼리가 좋은지? 에 대한 갑론을박이 있었다.

사실 동적쿼리의 장점은 속도라고 말할 수 있었는데, 진행하고 있던 프로젝트의 전체적인 프로시저를 동적쿼리에서 정적쿼리로 바꾼적이 있다.

그 이유는 실행계획에 이유가 있었는데...정확한 이유는 기억 못하겠다.

여튼, 동적쿼리든 정적쿼리든 상황에 맞게 잘 사용해야겠다. 개발에는 100%라는 것이 없기에...

 

'Database > Query' 카테고리의 다른 글

동적 쿼리2  (0) 2020.08.27
누락된 인덱스 정보 확인  (0) 2020.08.27
SQL Server 요일  (0) 2020.08.27
INDEX 인덱스 모니터링  (0) 2020.08.27
프로시저 생성 권한 부여  (0) 2020.08.27

(DATENAME,DATEPART)

 

SQL Server에서 특정 일자의 요일을 구하고 싶을 때 DATENAME 혹은 DATEPART 함수를 사용하면 된다.

SELECT DATENAME(WEEKDAY,GETDATE())

 

DATENAME의 경우 SQL Server의 언어 설정에 따라 한국어일 경우 '월요일', '화요일'로 표기되지만

영어일 경우 'Monday', 'Tuesday' 처럼 표기되기 때문에 실제론 DATEPART를 많이 사용한다.

SELECT DATEPART(WEEKDAY,GETDATE())

DATEPART는 일요일 시작으로 순서대로 1(일),2(월),3(화),4(수),5(목),6(금),7(토)로 출력해준다.

 

 

 

 

필자는 보통 '월요일' 전체를 가져오기보단 '(월)' 이런 식으로 가져오기 때문에

아래와 같은 쿼리 혹은 Function을 만들어 사용한다.

SELECT CASE WHEN(DATEPART(WEEKDAY,GETDATE()) = '1') THEN '(일)'

            WHEN(DATEPART(WEEKDAY,GETDATE()) = '2') THEN '(월)'

            WHEN(DATEPART(WEEKDAY,GETDATE()) = '3') THEN '(화)'

            WHEN(DATEPART(WEEKDAY,GETDATE()) = '4') THEN '(수)'

            WHEN(DATEPART(WEEKDAY,GETDATE()) = '5') THEN '(목)'

            WHEN(DATEPART(WEEKDAY,GETDATE()) = '6') THEN '(금)'

            WHEN(DATEPART(WEEKDAY,GETDATE()) = '7') THEN '(토)' END AS DATENAME

 

'Database > Query' 카테고리의 다른 글

동적 쿼리2  (0) 2020.08.27
누락된 인덱스 정보 확인  (0) 2020.08.27
동적쿼리  (0) 2020.08.27
INDEX 인덱스 모니터링  (0) 2020.08.27
프로시저 생성 권한 부여  (0) 2020.08.27

-- 인덱스에대해카운터가되었는지확인

-- Index_id NULL 인경우는인덱스를타지않은경우, NULL 이아닌경우는인덱스를탄경우

select object_name( idx.object_id) as 'table',

idx.name as 'index',

idx.index_id as 'id',

idx.type_desc as 'type',

icol.column_id,

--col.name,

usg.user_seeks,

usg.last_user_seek,

usg.user_scans,

usg.last_user_scan,

usg.user_lookups,

usg.last_user_lookup

from sys.indexes idx inner join sys.dm_db_index_usage_stats usg

on usg.object_id = idx.object_id and idx.index_id = usg.index_id and usg.database_id = db_id()

left join sys.index_columns icol on icol.index_id = usg.index_id and icol.object_id = idx.object_id

and usg.index_id IS null

and idx.type_desc not in ('heap','clustered')

'Database > Query' 카테고리의 다른 글

동적 쿼리2  (0) 2020.08.27
누락된 인덱스 정보 확인  (0) 2020.08.27
동적쿼리  (0) 2020.08.27
SQL Server 요일  (0) 2020.08.27
프로시저 생성 권한 부여  (0) 2020.08.27
GRANT CREATE VIEW TO [UserName];

GRANT CREATE PROCEDURE TO [UserName];

GRANT ALTER ON SCHEMA::[dbo] TO [UserName];

GRANT EXECUTE ON [procedure_Name] TO [UserName];

'Database > Query' 카테고리의 다른 글

동적 쿼리2  (0) 2020.08.27
누락된 인덱스 정보 확인  (0) 2020.08.27
동적쿼리  (0) 2020.08.27
SQL Server 요일  (0) 2020.08.27
INDEX 인덱스 모니터링  (0) 2020.08.27

+ Recent posts