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

활동 모니터를 보면 최근에 비싼 쿼리와 쿼리 열 아래에 "fetch api_cursor0000000000000003"이 표시됩니다. 이게 뭐야? 이 쿼리 뒤에 무엇이 실행되고 있는지 어떻게 알 수 있습니까?

분명히 그 질문의 힌트는 "Fetch and Cursor"키워드였습니다. 그래서 시작점이 무엇인지 알았습니다. 쿼리를 추적하고 싶지만 프로파일 러를 캡처하거나 sys.sysprocesses 또는 DBCC INPUTBUFFER의 기존 방법을 사용하면 다음과 같은 상황이 몇 번이나 나타납니다.

프로파일 러에서도 똑같은 것은 아래와 같습니다.

EXEC sp_cursorfetch 180150003,16,8,1

또는

FETCH API_CURSOR0000000000000001

참고 : 쿼리의 숫자는 환경에 따라 다를 수 있습니다. 다음은 문제를 시뮬레이션하는 VBScript 코드입니다.

Dim strConnection
Dim MyConnection
Dim MyRecordSet
Dim strSQL
strConnection = “Provider=SQLOLEDB;Data Source=.\SQL2014;Initial Catalog=Master;Integrated Security=SSPI;”
Set MyConnection = CreateObject(“ADODB.Connection”)
MyConnection.Open strConnection
Set MyRecordSet = CreateObject(“ADODB.recordset”)
strSQL = “SELECT TOP 3 * FROM sysobjects”
MyRecordSet.Cursorlocation = 2
MyRecordSet.Open strSQL, MyConnection, 3,3
MyRecordSet.MoveFirst
WHILE NOT MyRecordSet.EOF
MsgBox(MyRecordSet(“name”).value)
MyRecordSet.MoveNext
WEND
MyRecordSet.Close
Set MyRecordSet = Nothing

문제를 재현하려면 위의 코드를 파일에 저장하고 확장명 .vbs를 유지할 수 있습니다. 그런 다음 명령 프롬프트에서 실행할 수 있습니다. 환경에 맞게 연결 문자열에서 Source 값을 변경해야 할 수 있습니다. VB 스크립트를 실행하면 테이블 이름이 포함 된 팝업이 표시됩니다. 프로파일 러가 처음부터 캡처 된 경우 쿼리를 알 수있는 sp_cursoropen이 표시되어야합니다. 쿼리가 이미 실행중인 경우 아래 쿼리를 사용할 수 있습니다.

SELECT creation_time,
cursor_id,
c.session_id,
c.properties,
c.creation_time,
c.is_open,
SUBSTRING(st.TEXT, ( c.statement_start_offset / 2) + 1, (
( CASE c.statement_end_offset
WHEN -1 THEN DATALENGTH(st.TEXT)
ELSE c.statement_end_offset
END - c.statement_start_offset) / 2) + 1) AS statement_text
FROM   sys.Dm_exec_cursors(0) AS c
JOIN sys.dm_exec_sessions AS s
ON c.session_id = s.session_id
CROSS apply sys.Dm_exec_sql_text(c.sql_handle) AS st
GO

 

다음은 샘플 실행입니다. 보시다시피 커서를 연 쿼리 텍스트를 얻을 수 있습니다.

 

참고 : cursor_id는 sp_cursorfetch에서 본 것과 동일합니다. 또한 전체 프로필을 캡처하면 아래 출력을 볼 수 있습니다.

쿼리가 시작된 이후 전체 프로파일 러를 보거나 캡처 sp_cursorfetch 하거나 sys.Dm_exec_cursors를 사용하여 정확한 쿼리를 가져옵니다.FETCH API_CURSOR0000000000000001 

'Database > SQL Server' 카테고리의 다른 글

In-Memory OLTP  (0) 2020.08.28
Backup Script  (0) 2020.08.28
index dmv  (0) 2020.08.27
운영 데이터 저장소 Vs 데이터 웨어하우스  (0) 2020.08.27
Ad-hoc 쿼리를 매개변수화 하여 성능 높이기  (0) 2020.08.27

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)

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

 

 

운영 데이터 저장소(ODS)

Data warehouse

ODS 는 온라인의(운영의) 데이터를 통합(수집) 한다.

일반적으로 온라인(운영의) 정보는 제공 하지 않는다. 오프라인 데이터(대량의 시계열 데이터) 를 제공한다.

ODS는 어떤 다른 시스템들이 직접적으로 접근하기 위해 요구되어 지는 시스템의 데이터로 사용되어 진다. 예) 다른 데이터베이스에 있는 데이터는 다양한 부분(시스템)들에 의해 갱신되어진다. 병원의 정산 업무 또는 다른 어떤 업무들을 실행하는 동안 이러한 것들이 요구되어 진다.

과거 데이터와 현재 데이터(조금 오래된 데이터, 시간 또는 몇일 전의 데이터) 로 의사 결정을 할 때 사용되어진다.

ODS 는 온라인 운영 (운영 업무)를 위한 데이터 저장소의 핵심이다.

운영 업무가 아닌 것에 사용된다.

 

Ad-hoc 쿼리를 매개변수화 하여 성능 높이기

 

  • Version : SQL Server 2005, 2008, 2008R2, 2012

 

많은 응용 프로그램에서 SQL Server에 연결하여 쿼리를 호출 한다. 보통 튜닝 가이드를 할 때 임의의 쿼리보다는 프로시저를 만들어서 호출 하기를 권장한다. 이러한 이유는 프로시저를 사용함으로써 여러 가지 이점이 있기 때문이다. 대표적인 예가 쿼리를 계속해서 컴파일 하지 않는다는 것이다. 컴파일에 따른 비용 절약과 플랜을 재사용 할 수 있기 때문에 SQL Server의 성능을 높일 수 있다.

 

일반적으로 날쿼리라 불리는 응용프로그램에서 매개변수화 하지 않는 쿼리를 요청 한다고 가정하자. 대부분의 쿼리는 같은 쿼리를 사용하면서 Where 절의 조건만 변형된 쿼리를 사용 할 것이다.

 

다음과 같이 동일한 쿼리에서 Where 절의 조건만 변형하여 호출 하여 보자.

(예제코드 : C#)

 

플랜캐쉬를 확인하여 플랜이 사용되고 있는지 확인 하자.

select qs.usecounts, cacheobjtype, objtype, qt.text

from sys.dm_exec_cached_plans qs

cross apply sys.dm_exec_sql_text(qs.plan_handle) as qt

order by qt.text

go

 

 

구문을 동일하나 Where 절의 조건에 따라 각 다르게 쿼리를 인식하여 플랜을 재사용하지 못하고 모든 쿼리를 컴파일 하여 사용 하였다.

 

 

쿼리를 매개변수화 시켜 호출 하여 보자.

 

 

Where 절이 다름에도 불구하고 처음 플랜을 생성한 뒤로 9번을 재사용한 것을 확인 할 수 있다.

프로파일러에서도 RPC 호출을 통하여 바인드된 것을 확인 할 수 있다.

 

 

DB튜닝을 하다 보면 데이터베이스뿐만 아니라 여러 응용 프로그램을 함께 수정해야 할 때가 많다. 처음 개발부터 이러한 환경의 차이를 알고 개발 한다면 성능에 여러 이점이 있으리라 생각한다.

 

[참고자료]

http://www.mssqltips.com/sqlservertip/1632/are-your-sql-server-application-queries-wasting-memory/

'Database > SQL Server' 카테고리의 다른 글

index dmv  (0) 2020.08.27
운영 데이터 저장소 Vs 데이터 웨어하우스  (0) 2020.08.27
온라인 인덱스 구성(Online Index)  (0) 2020.08.27
MSSQL TEMPDB DBFILE 삭제  (0) 2020.08.27
인덱스  (0) 2020.08.27

SQL Server AlwaysOn synchronous-commit 환경에서 동기화 레이턴시 트러블슈팅 Version : SQL Server 

 

SQL Server AlwaysOn synchronous-commit(동기 커밋) 환경에서HADR_SYNC_COMMIT 대기 정보를 이용해서 레이턴시 상태를 확인할 수 있다.

HADR_SYNC_COMMIT대기는 SQL Server가 원격 복제본의 신호가 트랜잭션을 커밋하기를 기다리고 있음을 나타낸다.

트래잭션 커밋 대기 시간에 대한 자세한 정보는 아래 링크를 확인한다.Troubleshooting High HADR_SYNC_COMMIT wait type with Always On Availability Groups : https://blogs.msdn.microsoft.com/sql_server_team/troubleshooting-high-hadr_sync_commit-wait-type-with-always-on-availability-groups/SQL Server 2012 AlwaysOn – Part 12 – Performance Aspects and Performance Monitoring II : https://blogs.msdn.microsoft.com/saponsqlserver/2013/04/24/sql-server-2012-alwayson-part-12-performance-aspects-and-performance-monitoring-ii/ 

 

위 두 링크를 살펴보면 트랜잭션 지연은 다음 두 성능 카운터로 평가하는 것을 알 수 있다.

SQL Server:Database Replica –> Transaction DelaySQL Server:Database Replica –> Mirrored Write Transactions/sec 예를 들어 AG에서 노드 성능이 좋지 않아 "SQL Server:Database Replica –> Transaction Delay = 1000ms" 이고 "SQL Server:Database Replica –> Mirrored Write Transactions/sec = 50"이라고 가정하면 평균적으로 트랜잭션 지연시간은 1000ms/50= 20ms 이다.

 

동기 커밋에 대한 자세한 정보는 아래 링크를 확인한다.AlwaysON – HADRON Learning Series: – How does AlwaysON Process a Synchronous Commit Request : https://blogs.msdn.microsoft.com/psssql/2011/04/01/alwayson-hadron-learning-series-how-does-alwayson-process-a-synchronous-commit-request/Update adds AlwaysOn extended events and performance counters in SQL Server 2014 or 2016 : https://support.microsoft.com/en-us/help/3173156/update-adds-alwayson-extended-events-and-performance-counters-in-sql-s 

 

아래 그림은 동기 커밋 모드에서 로그 블록이 Replica 서버에 커밋 되는 각 단계마다 XEvent가 캡쳐 되는 흐름을 보여준다.

 

 

 위 그림에서 살펴보면 XEvent 추적이 캡처되면 로그 블록 이동의 각 단계에서 중요한 시점을 알 수 있으므로 트랜잭션 대기 시간의 정확한 위치를 알 수 있다. 일반적으로 지연은 세 부분으로 나누어진다.

Primary 서버에서 log harden 지속 시간 Log_flush_start(step 2) 및 Log_flush_complete(step 3)의 델타 시간은 동일하다.

Replica 서버에서 log harden 지속 시간 Log_flush_start(step 10) 및 Log_flush_complete(step 11)의 델타 시간은 동일하다.

네트워크 트래픽의 지속 시간 Primary : hadr_log_block_send_complete ->secondary:hadr_transport_receive_log_block_message (step 6-7)Secondary : hadr_lsn_send_complete->primary:hadr_receive_harden_lsn_message (step 12-13)

 

 아래 스크립트는XEvent를 사용하여 각 단계에 소요되는 시간을 캡처할 수 있다.

/* Note: this trace could generate very large amount of data very quickly, depends on the actual transaction rate. On a busy server it can grow several GB per minute, so do not run the script too long to avoid the impact to the production server. */  CREATE EVENT SESSION [AlwaysOn_Data_Movement_Tracing] ON SERVER ADD EVENT sqlserver.file_write_completed, ADD EVENT sqlserver.file_write_enqueued, ADD EVENT sqlserver.hadr_apply_log_block, ADD EVENT sqlserver.hadr_apply_vlfheader, ADD EVENT sqlserver.hadr_capture_compressed_log_cache, ADD EVENT sqlserver.hadr_capture_filestream_wait, ADD EVENT sqlserver.hadr_capture_log_block, ADD EVENT sqlserver.hadr_capture_vlfheader, ADD EVENT sqlserver.hadr_db_commit_mgr_harden, ADD EVENT sqlserver.hadr_db_commit_mgr_harden_still_waiting, ADD EVENT sqlserver.hadr_db_commit_mgr_update_harden, ADD EVENT sqlserver.hadr_filestream_processed_block, ADD EVENT sqlserver.hadr_log_block_compression, ADD EVENT sqlserver.hadr_log_block_decompression, ADD EVENT sqlserver.hadr_log_block_group_commit , ADD EVENT sqlserver.hadr_log_block_send_complete, ADD EVENT sqlserver.hadr_lsn_send_complete, ADD EVENT sqlserver.hadr_receive_harden_lsn_message, ADD EVENT sqlserver.hadr_send_harden_lsn_message, ADD EVENT sqlserver.hadr_transport_flow_control_action, ADD EVENT sqlserver.hadr_transport_receive_log_block_message, ADD EVENT sqlserver.log_block_pushed_to_logpool, ADD EVENT sqlserver.log_flush_complete , ADD EVENT sqlserver.log_flush_start, ADD EVENT sqlserver.recovery_unit_harden_log_timestamps ADD TARGET package0.event_file(SET filename=N'c:\mslog\AlwaysOn_Data_Movement_Tracing.xel',max_file_size=(500),max_rollover_files=(4)) WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=ON)  GO

 아래 그림은 XEvent를 실행하여 캡처한 결과이다.[Primary]

 

 [Second synchronous replica]

 

 참고로 hadr_receive_harden_lsn_message의 log_block_id(14602889512)가 다른 ID(146028889488)와 동일하지 않는데, 그이유는 항상 다음의 harden log block의ID를 즉시 반환하기 때문이다. hadr_db_commit_mgr_update_harden xevent를 사용하여 XEvent를 상호연관 시킬 수 있다.

 

 

위의 XEvent 로그를 사용하여 캡처한 데이터를 사용하여 아래 표처럼 만들어서 트랜잭션 커밋의 상세한 지연시간을 확인할 수 있다. 이 리스트는 네트워크 및 log harden process의 시간 델타(latency)를 나열한 것이며 로그 블록의 압축이나 해제 등 다른 시간이 발생할 수도 있다.

 

From

To

Lantency

Network: Primary->Secon

Primary: hadr_log_block_send_complete  2018-03-06 16:56:28.2174613

Secondary: hadr_transport_receive_log_block_message  2018-03-06 16:56:32.1241242

3.907 seconds

Network: Secondary->Primary

Secondary:hadr_lsn_send_complete 2018-03-06 16:56:32.7863432

Primary:hadr_receive_harden_lsn_message 2018-03-06 16:56:33.3732126

0.587 seconds

LogHarden(Primary)

log_flush_start 2018-03-06 16:56:28.2168580

log_flush_complete 2018-03-06 16:56:28.8785928

0.663 seconds

Log Harden(Secondary)

Log_flush_start 2018-03-06 16:56:32.1242499

Log_flush_complete 2018-03-06 16:56:32.7861231

0.663 seconds

 위에서 언급했든이 주로 발생하는 대기시간은 다음 세 부분에서 발생한다.복제본간의 네트워크 대기시간 : 3.907 + 0.857 = 4.494Primary Log harden : 0.663Secondary Log harden : 0.663 총 트랜잭션 지연시간을 얻기에는Primary 로그 플러시와 네트워크 전송이 동시에 발생하기 때문에 합산할 수 없어 쉽지 않다.

 

네트워크에서 4.494초가 발생하였고, Primary가 복제본으로부터 컨펌(hadr_receive_harden_lsn_message:2018-03-06 16:56:33.3732126)을 받고 완료한 시간을 (log_flush_complete : 2018-03-06 16 : 56 : 28.8785928) 시간을 계산할때 타임스탬프를 수동으로 계산할 필요가 없다.

 

XEvent는 두 개의 hadr_log_block_group_commit사이의 델타시간을 알 수 있기 때문이다. 아래 예시를 살펴보자.Primary: hadr_log_block_group_commit: 2018-03-06 16:56:28.2167393Primary: hadr_log_block_group_commit: 2018-03-06 16:56:33.3732847Total time to commit=delta of above two timestamps= 5.157 seconds 이 숫자는 네트워크 전송 시간과Secondary서버의 log harden을 더한것과 같다. 그 이유는Secondary 서버의log harden 가 네트워크를 사용할 수 있기를 기다려야하므 Primary와 마찬가지로 동시에 log harden를 할 수 없기 때문이다.

 

 

지금까지 AlwaysOn 동기-커밋 모드에서 복제본간 로그 블록 이동에 대해서 살펴보았다.

그런데 Primary 서버의 XEvent에서 "hadr_db_commit_mgr_harden_still_waiting"가 가끔 발생하는 것을 볼수 있는데 이 이벤트는 Primary 서버가 Secondary 복제본의 확인 메시지를 기다리고 있을때 2초 간격으로 발생(2초로 하드코딩 되어있음)한다. 2초 내에 Ack이 돌아오면 XEvent에 표시되지 않는다. 

 

[참고자료]https://blogs.msdn.microsoft.com/psssql/2018/04/05/troubleshooting-data-movement-latency-between-synchronous-commit-always-on-availability-groups/

SQL 2005 부터 인덱스와 관련하여 개선된 기능 중 하나인 온라인 인덱스 작업에 대하여 알아 보겠습니다. 온라인 인덱스 작업은 1년 365일 운영되어야 하는 시스템을 관리하는 DBA들에게 획기 적인 기능입니다. 온라인 인덱스를 할수 있게 됨으로써 다운 타임을 감소할수 있게 되었으며 인덱스를 재구성할려고 할때도 소요 시간 때문에 많은 고민을 해야 하는 수고를 덜어 줄수 있게 되었습니다. Create Index , Alter Index , Drop index Alter Table 명령어에서 ONLINE 옵션을 사용할수 있습니다.

온라인 인덱스 구성 vs. 오프라인 인덱스 구성ONLINE 옵션은 이러한 인덱스 작업을 수행하는 동안에도 사용자가 테이블이나 클러스터형(Clustered) 인덱스와 관련된 비클러스터형(Nonclustered) 인덱스에 접근할수 있습니다. 오프라인으로 클러스터형 인덱스를 구성하거나 재구성하는 등의 DDL 작업을 하면 이는 해당 데이터와 관련 인덱스에 배타적 잠금을 보유하게 되고 이로 인해 다른 사용자가 데이터나 인덱스에 접근하지 못하도록 방해하게 된다.

Example:

CREATE INDEX idx_t ON t(c1, c2)

WITH (ONLINE = ON)

 

일반 인덱스 구성 vs. 병렬 인덱스 구성멀티 프로세서를 가진 SQL서버에서 인덱스 구문 또한 다른 쿼리를 실행할 때처럼, 스캔, 정렬, 그리고 구성 작업을 수행하는데 병렬 처리가 가능 해졌습니다. 병렬 처리 수는 최대 병렬 처리 수(sp_configure로 설정한), MAXDOP 인덱스 옵션, 현재 작업부하의 크기, 파티션되지 않은 경우, 첫 번째 키 칼럼의 데이터 분포등에 의해서 결정될 수 있다.

 

Example:

CREATE INDEX idx_t ON t(c1, c2)

WITH (MAXDOP = 2)

-- 인덱스 구성에 2개의 프로세서 사용

 

온라인 인덱스 가능한 SQL 버전Microsoft SQL Server 2005 Enterprise Edition

 

온라인 인덱스는 어떻게 동작 할까?

 

 

인덱스 DDL(데이터 정의 언어) 작업 중에 동시 사용자 작업이 가능하도록 하려면 온라인 인덱스 작업 중에 원본 및 기존 인덱스, 대상 및 임시 매핑 인덱스(클러스터형 인덱스의 경우) 로 구성됨으로써 온라인 인덱스 작업 수행을 할수 있도록 합니다.

원본 및 기존 인덱스원본은 원래 테이블이거나 클러스터형 인덱스 데이터입니다. 기존 인덱스는 원본 구조와 관련된 모든 비클러스터형 인덱스입니다. 예를 들어 온라인 인덱스 작업이 네 개의 관련 비클러스터형 인덱스가 있는 클러스터형 인덱스를 재구성하는 것이라면 원본은 기존 클러스터형 인덱스이고 기존 인덱스는 비클러스터형 인덱스입니다.기존 인덱스는 여러 사용자의 동시 선택, 삽입, 업데이트 및 삭제 작업에 사용됩니다. 여기에는 대량 삽입(지원되지만 권장하지 않음)과 트리거 및 참조 무결성 제약 조건에 의한 암시적 업데이트가 포함됩니다. 쿼리와 검색에 모든 기존 인덱스를 사용할 수 있습니다. 즉, 기존 인덱스를 쿼리 최적화 프로그램에서 선택할 수 있으며 필요한 경우 인덱스 힌트에 지정할 수 있습니다.

대상대상은 만들거나 다시 작성하는 새 인덱스(또는 힙)이거나 새 인덱스 집합입니다. SQL Server 데이터베이스 엔진에서는 인덱스 작업을 수행하는 동안 원본에 대한 사용자 삽입, 업데이트 및 삭제 작업을 대상에 적용합니다. 예를 들어 온라인 인덱스 작업이 클러스터형 인덱스를 다시 작성하는 것이라면 대상은 다시 작성되는 클러스터형 인덱스입니다. 데이터베이스 엔진에서는 클러스터형 인덱스를 다시 작성할 때 비클러스터형 인덱스를 다시 작성하지 않습니다.대상 인덱스는 인덱스 작업이 커밋될 때까지 SELECT 문을 처리하는 동안 검색되지 않습니다. 내부적으로 인덱스가 쓰기 전용으로 표시됩니다.

임시 매핑 인덱스클러스터형 인덱스를 만들거나 삭제하거나 다시 작성하는 온라인 인덱스 작업에는 임시 매핑 인덱스도 필요합니다. 이러한 임시 인덱스는 동시 트랜잭션이 기본 테이블의 행이 업데이트되거나 삭제될 때 작성되는 새 인덱스에서 삭제할 레코드를 결정하는 데 사용합니다. 이러한 비클러스터형 인덱스는 새 클러스터형 인덱스(또는 힙)와 같은 단계에서 만들어지므로 별도의 정렬 작업이 필요 없습니다. 동시 트랜잭션의 모든 삽입, 업데이트 및 삭제 작업에서도 임시 매핑 인덱스가 유지됩니다.

 

참고 사이트

 

http://blogs.msdn.com/sqlqueryprocessing/archive/2006/11/08/index-build-strategy-in-sql-server-introduction-i.aspxhttp://technet.microsoft.com/ko-kr/library/ms191261.aspx

 

 

출처: https://gdbt.tistory.com/68 [Gravity DB Team]

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

머신 사양들이 좋아지면서 해당 리소스를 충분히 활용하기 위해 

 

 

 

그리고 mssql 의 성능 향상을 위해 tempdb 파일을 늘리는데.. 

 

 

 

여러 자료를 조합해 본 결과 tempdb 의 데이터 파일은 머신의 코어 수와 맞추면 된단다..

 

 

 

단 요즘은 코어가 하도 많아서... 8개 이상은 의미가 없다... 고 한다 

 

 

 

뭐 스트레스 테스트까지는 해보지 않아서 정확한건 모르겠지만.. 

 

 

 

선인들이 해보셨으면 나도 비슷하다 생각하고... 파일을 늘려놨는데...

 

 

 

 

 

파일 늘리기 전 상황을 캡쳐해놓은것이 없어 파일을 늘린것이 얼마나 효과가 있는지 잘 모르겠다.. 

 

 

 

그래서 역으로 테스트를 해보려 한다.. 

 

(tempdb datafile이 8개인경우 먼저 캡쳐 && 4개 줄여서 테스트 ㅋㅋ)

 

 

 

근데 웃긴건 tempdb datafile 이 만들때는 잘 만들어지는데 지워지지 않는다 ㅋㅋㅋㅋㅋ

 

 

 

 

 

 

 

그래서 잘~~~ 찾아보니.. datafile이 비어지지 않아서란다 ㅋㅋㅋ

 

 

 

자동으로 비우고 해주면 되지... 알파고도 나온마당에 뭘 또 에러 띄우고 그러시나.. 

 

 

 

 

 

암튼 지우기 전에 아래의 쿼리를 실행하고 돌리쟈.. 

 

 

 

==================================================================

 

USE [tempdb]

 

GO

 

DBCC SHRINKFILE ([데이터파일명], EMPTYFILE);

 

GO

 

 

 

use [master]

 

ALTER DATABASE [tempdb]  REMOVE FILE [데이터파일명]

 

 

 

GO

 

===================================================================

 

 

 

그럼 겁내 잘지워진다 ㅎㅎㅎㅎ

 

 

 

 

 

 

 

근데... 실제 사용자들이 사용하는 DB는 아래의 메세지와 함께 또.. 지워지지 않는다.. 

 

 

 

=========================================================================================

 

 

 

DBCC SHRINKFILE: 페이지 9:1320은(는) 작업 테이블 페이지이므로 이동할 수 없습니다.

 

메시지 2555, 수준 16, 상태 2, 줄 3

 

파일 "tempdb8"의 일부 내용을 다른 위치로 이동할 수 없어 emptyfile 작업을 완료할 수 없습니다.

 

DBCC 실행이 완료되었습니다. DBCC에서 오류 메시지를 출력하면 시스템 관리자에게 문의하십시오.

 

 

 

==========================================================================================

 

 

 

이유인 즉슨.. 해당 데이터파일이 사용중이다..(내지는 다른데가 사용중이라 비울수 없다..)

 

 

 

그래서 찾아보니... (http://sqlserverzest.com/2012/10/07/msg-2555-level-16-state-1-line-1-error-dbcc-shrinkfile-with-emptyfile-option/

 

 

 

위와 같은 메세지가 날때는 

 

 

 

1. 외부 커넥션을 다 끊던지..

 

2. 서버를 재시작 하라고 하신다 ㅎㅎㅎㅎ

 

 

 

실운영 서버라 테스트는 못했지만.. 꼭 필요한 경우라면 진행 가능할듯 하다. ㅎ

 

 

 

그럼 오늘의 정리는 이만 ㅎ

 

'Database > SQL Server' 카테고리의 다른 글

Ad-hoc 쿼리를 매개변수화 하여 성능 높이기  (0) 2020.08.27
온라인 인덱스 구성(Online Index)  (0) 2020.08.27
인덱스  (0) 2020.08.27
쿼리 저장소 (Query Store)  (0) 2020.08.27
모든 DB의 로그 잘림 확인하기  (0) 2020.08.27

+ Recent posts