[SQL][問題處理]肥得要死的 tempdb 如何縮減

https://dotblogs.com.tw/jamesfu/2014/05/20/shrinktempdb

可以參考 Technet 上的文章,一般來說當你連線結束之後,所佔用的資源應該會被釋放,但目前他們的 tempdb 會長到那麼大的話,我們直接使用壓縮指令又無法壓縮的狀況下,因此建議朋友先使用以下的指令來試試看:

-- 避免還有資料還在記憶體內,手動進行 Checkpoint
Checkpoint
GO

-- 強制釋放佔用的記憶體
DBCC FREESYSTEMCACHE ('ALL')
DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS
DBCC FREESESSIONCACHE
GO

完成上述指令之後,再重新進行一次壓縮 tempdb,果然就可以順利把 tempdb 給壓縮了。

DBCC SHRINKDATABASE(N'tempdb')

SQL TABLE內資料的全文檢索

https://blog.miniasp.com/post/2010/07/12/Search-all-columns-of-all-tables-in-a-database-for-a-keyword.aspx

感謝保哥,讚嘆保哥

DECLARE @SearchStr nvarchar(200) = N'使用者本文'


-- Copyright © 2002 Narayana Vyas Kondreddi. All rights reserved.
-- Purpose: To search all columns of all tables for a given search string
-- Written by: Narayana Vyas Kondreddi
-- Site: http://vyaskn.tripod.com
-- Tested on: SQL Server 7.0 and SQL Server 2000
-- Date modified: 28th July 2002 22:50 GMT


CREATE TABLE #Results (ColumnName nvarchar(370), ColumnValue nvarchar(3630))

SET NOCOUNT ON

DECLARE @TableName nvarchar(256), @ColumnName nvarchar(128), @SearchStr2 nvarchar(110)
SET  @TableName = ''
SET @SearchStr2 = QUOTENAME('%' + @SearchStr + '%','''')

WHILE @TableName IS NOT NULL
BEGIN
	SET @ColumnName = ''
	SET @TableName = 
	(
		SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
		FROM 	INFORMATION_SCHEMA.TABLES
		WHERE 		TABLE_TYPE = 'BASE TABLE'
			AND	QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > @TableName
			AND	OBJECTPROPERTY(
					OBJECT_ID(
						QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)
						 ), 'IsMSShipped'
					       ) = 0
	)

	WHILE (@TableName IS NOT NULL) AND (@ColumnName IS NOT NULL)
	BEGIN
		SET @ColumnName =
		(
			SELECT MIN(QUOTENAME(COLUMN_NAME))
			FROM 	INFORMATION_SCHEMA.COLUMNS
			WHERE 		TABLE_SCHEMA	= PARSENAME(@TableName, 2)
				AND	TABLE_NAME	= PARSENAME(@TableName, 1)
				AND	DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar')
				AND	QUOTENAME(COLUMN_NAME) > @ColumnName
		)

		IF @ColumnName IS NOT NULL
		BEGIN
			INSERT INTO #Results
			EXEC
			(
				'SELECT ''' + @TableName + '.' + @ColumnName + ''', LEFT(' + @ColumnName + ', 3630) 
				FROM ' + @TableName + ' (NOLOCK) ' +
				' WHERE ' + @ColumnName + ' LIKE ' + @SearchStr2
			)
		END
	END	
END

SELECT * FROM #Results

DROP TABLE #Results

LINK SERVER的怪問題

情境:
LINK到另一台的SP將SELECT結果取回入TEMP,但會出現”無法執行作業,因為連結伺服器 “ESWEB1” 的 OLE DB 提供者 “SQLNCLI10” 無法開始分散式交易。”的錯誤訊息
改DTC也無效(https://dotblogs.com.tw/abbee/2017/01/20/163135)

EXEC sp_configure
exec sp_configure 'show advanced options', 1;
RECONFIGURE;
exec sp_configure 'Ad Hoc Distributed Queries', 1;
RECONFIGURE;
GO

原語法:

insert into #tmp
exec [link].SP

改為OPENQUERY:

insert into #tmp
select * from openquery([link],'SET FMTONLY OFF;SET NOCOUNT ON;exec SP')

最大群組關聯

近期遇到最難的邏輯

if object_id('tempdb..#IL_Benson') is not null
	drop table #IL_Benson ;

create table #IL_Benson (
	ActSeq varchar(19) --18
	, GCNo varchar(21) --21
	, ActSeq_T varchar(19)
	, GCNo_T varchar(21)
	, RUN int default 0) ;

insert into #IL_Benson (ActSeq, GCNo)
values ('ACT1', 'A')
, ('ACT2', 'B'), ('ACT2', 'C'), ('ACT2', 'D')
, ('ACT3', 'A'), ('ACT3', 'C')
, ('ACT4', 'D')
, ('ACT5', 'D'), ('ACT5', 'E')
, ('ACT6', 'F'), ('ACT6', 'G')
, ('ACT7', 'F')
, ('ACT8', 'G'), ('ACT8', 'H')
, ('ACT9', 'Z')

/*
update a
set a.RUN = 0
	, a.ActSeq_T = null
	, a.GCNo_T = null
from #IL_Benson a

select a.ActSeq, a.GCNo, a.ActSeq_T, a.GCNo_T, a.RUN
from #IL_Benson a
order by 1, 2
*/
--資料檢測,RUN<0
--(RUN=-1) 1 ACT to 1 GC
update a
set a.ActSeq_T = a.ActSeq
	, a.GCNo_T = a.GCNo
	, a.RUN = -1
from #IL_Benson a
inner join (
	select a.ActSeq, count(distinct  a.GCNo) CNT
	from #IL_Benson a
	group by a.ActSeq
	having count(distinct  a.GCNo) = 1 ) b
	on a.ActSeq = b.ActSeq
inner join (
	select a.GCNo, count(distinct a.ActSeq) CNT
	from #IL_Benson a
	group by a.GCNo
	having count(distinct  a.ActSeq) = 1 ) c
	on a.GCNo = c.GCNo
;

--(RUN=-2) 1 ACT to Multi GC and 1 GC to 1 ACT
update a
set a.ActSeq_T = a.ActSeq
	, a.GCNo_T = b.GCNo_T
	, a.RUN = -2
--select count(*)
from #IL_Benson a
inner join (
	select a.ActSeq, count(distinct  a.GCNo) CNT, min(a.GCNo) GCNo_T
	from #IL_Benson a
	group by a.ActSeq
	having count(distinct  a.GCNo) > 1 ) b
	on a.ActSeq = b.ActSeq
inner join (
	select b.ActSeq, count(distinct a.ActSeq) cnt
	from #IL_Benson a
	inner join (
		select a.ActSeq, a.GCNo
		from #IL_Benson a
		inner join (
			select a.ActSeq, count(distinct  a.GCNo) CNT
			from #IL_Benson a
			group by a.ActSeq
			having count(distinct  a.GCNo) > 1 ) b
			on a.ActSeq = b.ActSeq ) b
		on a.GCNo = b.GCNo
	group by b.ActSeq
	having count(distinct a.ActSeq) = 1 ) c
	on a.ActSeq = c.ActSeq
where a.ActSeq_T is null
and a.GCNo_T is null
;

--(RUN=-3) 1 ACT to 1 GC and 1 GC to Multi ACT
update a
set a.ActSeq_T = b.ActSeq_T
	, a.GCNo_T = a.GCNo
	, a.RUN = -3
--select count(*)
from #IL_Benson a
inner join (
	select a.GCNo, count(distinct a.ActSeq) CNT, min(a.ActSeq) ActSeq_T
	from #IL_Benson a
	group by a.GCNo
	having count(distinct  a.ActSeq) > 1 ) b
	on a.GCNo = b.GCNo
inner join (
	select b.GCNo, count(distinct a.GCNo) cnt
	from #IL_Benson a
	inner join (
		select a.ActSeq, a.GCNo
		from #IL_Benson a
		inner join (
			select a.GCNo, count(distinct a.ActSeq) CNT
			from #IL_Benson a
			group by a.GCNo
			having count(distinct a.ActSeq) > 1 ) b
			on a.GCNo = b.GCNo ) b
		on a.ActSeq = b.ActSeq
	group by b.GCNo
	having count(distinct a.GCNo) = 1
	) c
	on a.GCNo = c.GCNo
where a.ActSeq_T is null
and a.GCNo_T is null
;

--select * from #IL_Benson
--------------------------------------
--補衍伸關聯資料,RUN=1
DECLARE @RC INT
DECLARE @RUN INT

select @RC = count(*)
--select count(*)
from #IL_Benson a
where a.ActSeq_T is null

WHILE @RC > 0
BEGIN

	SET @RC = 0

	insert into #IL_Benson (ActSeq, GCNo, RUN)
	select distinct b.ActSeq_T ActSeq, a.GCNo, 1
	from #IL_Benson a
	inner join (
		select distinct b.ActSeq ActSeq_T, a.ActSeq, b.GCNo
		from #IL_Benson a
		inner join (
			select distinct a.ActSeq, a.GCNo
			from #IL_Benson a
			where a.ActSeq_T is null
			--and a.ActSeq = '3'
			) b
			on a.GCNo = b.GCNo ) b
		on a.ActSeq = b.ActSeq
	left outer join #IL_Benson c
		on b.ActSeq_T = c.ActSeq
		and a.GCNo = c.GCNo
		and c.ActSeq_T is null
	where a.ActSeq_T is null
	and c.ActSeq is null

	set @RC = @RC + @@ROWCOUNT
	--select * from #IL_Benson where Run=1

	insert into #IL_Benson (ActSeq, GCNo, RUN)
	select distinct a.ActSeq, b.GCNo_T GCNo, 1
	from #IL_Benson a
	inner join (
		select distinct b.GCNo GCNo_T, b.ActSeq, a.GCNo
		from #IL_Benson a
		inner join (
			select distinct a.ActSeq, a.GCNo
			from #IL_Benson a
			where a.ActSeq_T is null
			--and a.GCNo = 'D'
			) b
			on a.ActSeq = b.ActSeq ) b
		on a.GCNo = b.GCNo
	left outer join #IL_Benson c
		on a.ActSeq = c.ActSeq
		and b.GCNo_T = c.GCNo
		and c.ActSeq_T is null
	where a.ActSeq_T is null
	and c.ActSeq is null

	set @RC = @RC + @@ROWCOUNT
	--select * from #IL_Benson where Run=1

	--select a.RUN, count(*)
	--from #IL_Benson a
	--where a.ActSeq_T is null
	--group by a.RUN
END

update a
set a.ActSeq_T = a.ActSeq
	, a.GCNo_T = a.GCNo
from #IL_Benson a
where a.ActSeq_T is null
and a.GCNo_T is null

--select * from #IL_Benson order by ActSeq_T,GCNo_T
--------------------------------------
declare @RC INT
select @RC = count(*)
from #IL_Benson a
where a.RUN >= 0
--select @RC

WHILE @RC > 0
BEGIN

	SET @RC = 0

	update a
	set a.ActSeq_T = b.ActSeq
	--select count(*)
	from #IL_Benson a
	inner join (
		select a.GCNo GCNo, min(a.ActSeq) ActSeq
		from #IL_Benson a
		where a.RUN >= 0
		group by a.GCNo ) b
		on a.GCNo_T = b.GCNo
		and a.ActSeq_T <> b.ActSeq
	where a.RUN >= 0

	SET @RC = @RC +  @@ROWCOUNT

	update a
	set a.GCNo_T = b.GCNo
	--select count(*)
	from #IL_Benson a
	inner join (
		select a.ActSeq ActSeq, min(a.GCNo) GCNo
		from #IL_Benson a
		where a.RUN >= 0
		group by a.ActSeq ) b
		on a.ActSeq_T = b.ActSeq
		and a.GCNo_T <> b.GCNo
	where a.RUN >= 0

	SET @RC = @RC +  @@ROWCOUNT

END

--select * from #IL_Benson order by ActSeq,GCNo

 

SQL Server中獲得EXEC的值

前言:
在資料庫程式開發的過程中,我們經常會碰到利用EXEC來執行一段需要返回某些值的sql語句(通常是構造動態sql語句時使用),或者在一個預存程序中利用EXEC調用另一個有傳回值的預存程序(必須獲得傳回值),那麼如何獲得這些傳回值呢?
1.EXEC執行sql語句的情況
declare @rsql Varchar(250)
declare @csql Varchar(300)
declare @rc Nvarchar(500)
declare @cstucount int
declare @ccount int
set @rsql='(select Classroom_id from EA_RoomTime where zc='+@zc+' and xq='+@xq+' and T'+@time+'=''否'') and ClassroomType=''1'''
--exec(@rsql)
set @csql='select @a=sum(teststucount),@b=sum(classcount) from EA_ClassRoom where classroom_id in '
set @rc=@csql+@rsql
exec sp_executesql @rc,N'@a int output,@b int output',@cstucount output,@ccount output--將exec的結果放入變數中的做法
--select @csql+@rsql

–select @cstucount上面的@rc這個sql語句的功能是找出特定時間段裡所有有空的教室數量以及這些教室所能容納的學生人數,因為涉及到動態的sql語句(@csql這句裡條件中有一個列名是動態變化的)的構造,所以要放在exec裡執行,但是同時我又要返回2個結果,所以執行時的代碼為:

exec sp_executesql @rc,N'@a int output,@b int output',@cstucount output,@ccount output--將exec的結果放入變數中的做法

這樣就將傳回值放到了,@cstucount,@ccount兩個變數中,得到了我們想要的結果。

 

2.exec執行帶傳回值的預存程序的情況

我們來看一個簡單的預存程序:

create procedure ProTest
(
@name Varchar(10),
@money int output
)
as
begin
if(@name='1')
  set @money=1000
else
  set @money=2000
end

這個只是一個簡單的示例,這個預存程序返回的是@money 這個參數的值,那麼當我們在另外一個預存程序中調用此預存程序的時候如何獲取這個參數呢,方法如下:

declare @m int ---用來接收傳回值的變數
exec ProTest @name='1',@money=@m output --一定要注名是output

就這麼簡單,我們就獲得了傳回值,然後就可以利用它了。