2011-06-23 210 views
0

在SQL Server 2008註釋sp_spaceused,我想迅速獲得一排用於在存儲過程中的診斷目的的表數。在存儲的過程我用下面的SQL獲得計數,而做一個表掃描:從調用存儲過程

--Get row count using sp_spaceused 
DECLARE @rowCount AS INT 
DECLARE @spaceUsed TABLE(
    [Name] varchar(64), 
    [Rows] INT, 
    [Reserved] VARCHAR(50), 
    [Data] VARCHAR(50), 
    [Index_Size] VARCHAR(50), 
    [Unused] VARCHAR(50) 
) 
INSERT INTO @spaceUsed EXEC sp_spaceused 'MyTable' 
SET @rowCount = (SELECT TOP 1 [Rows] FROM @spaceUsed) 

這個SQL工作得很好,當我使用管理員帳戶執行從SQL Management Studio中存儲過程。但是,當我嘗試從代碼(使用其他登錄名)執行存儲過程時,sp_spaceused失敗,並顯示消息「對象'MyTable'在數據庫'MyDatabase'中不存在或對此操作無效。

有沒有一種方法,使這項工作對非管理員聯繫登錄?還有什麼我錯過了在管理工作室與代碼運行過程?

+1

不用戶有權限MyTable?您是否試過在表中包含模式名稱(例如'dbo.MyTable')? –

+0

@Tom H .:看起來用戶對錶格的權限是問題。我授予完全訪問正在執行代碼調用的用戶的權限,並且它可以正常工作。只需要現在回去並找出我需要設置的最低級別的權限。如果您發表評論作爲答案,我會接受。 – rsbarro

回答

1

你需要確保主叫用戶有權限,你正在檢查的表。讀取權限應該足以滿足你正在做的事情,但我沒有測試過。

正如其他人所說,你也可以使用EXECUTE AS如果表中的數據是安全的性質,你不希望用戶擁有甚至閱讀訪問它。

+0

從我的測試中,我能夠通過授予'Select','View Definition'或'View Change Tracking'權限(最後一個我沒有想到的工作)來執行sp_spaceused。它幾乎看起來像你只需要授予對sp_spaceused的表的任何訪問權限以便爲該用戶工作。由於數據不敏感,我將使用SELECT訪問。謝謝您的幫助! – rsbarro

+0

從它的聲音,我會認爲視圖定義會更有意義,但它顯然是您的呼叫 –

+0

@rsbarro_如果您使用UDF來隱藏sys調用,則不需要GRANT *任何*權限。按照我的啓動器 – gbn

1

當你在SSMS之外運行時,你確定你在正確的數據庫嗎?

儘管the docs說「執行sp_spaceused的權限授予公共角色」,但這似乎與您看到的內容相矛盾。

一種選擇是把它放在一個存儲過程,並使用EXECUTE AS功能得到它執行爲管理員。

+0

用於EXECUTE AS的+1。謝謝。 – rsbarro

4

你嘗試使用對象的前綴(如EXEC註釋sp_spaceused 'dbo.MyTable')?如果用戶無權訪問該對象的模式或具有與dbo不同的默認模式,則會發生這種情況。

你嘗試創建與EXECUTE AS程序?

順便說一句,而不是一遍一遍調用此存儲過程,爲什麼不從sys.dm_db_partition_stats拉數據,其中index_id的IN(0,1)?這樣做後,你的頁面數(這可以很容易產生相同的信息),並且不需要執行程序,數據轉儲到#TEMP表的所有腳手架。

+0

+1,程序'sp_spaceused'使用'sys.dm_db_partition_stats'獲取一些值,檢查SSMS中的源代碼,轉到數據庫msdb,然後是可編程性,然後是存儲過程,然後是系統存儲過程,然後是sys.sp_spaceused,然後修改。你可以看到他們正在做的一切。只需在sp_spaceused中包含所需的sql代碼中的所有內容即可。 –

+0

對於EXECUTE AS來說是+1,但是這種方法不會像爲我的特定場景授予對錶格的訪問權限。感謝你的回答。 – rsbarro

1

有更簡單的方法。

鑑於註釋sp_spaceused內部調用sys.dm_db_partition_stats,你可以運行這個命令:

SELECT 
    @rowCount = SUM(st.row_count) 
FROM 
    sys.dm_db_partition_stats st 
WHERE 
    object_name(object_id) = 'Mytable' AND (index_id < 2) 

您可以在我的答案在這裏使用UDF

CREATE FUNCTION dbo.GetCounts (@tablename varchar(100)) 
RETURNS bigint 
WITH EXECUTE AS OWNER 
AS 
BEGIN 
    RETURN (
    SELECT 
     SUM(st.row_count) 
    FROM 
     sys.dm_db_partition_stats st 
    WHERE 
     object_name(object_id) = @tablename AND (index_id < 2) 
    ) 
END 
GO 

更多隱藏權限:Fastest way to count exact number of rows in a very large table?

+0

只是一個建議:因爲看起來海報可能會遇到跨架構權限(並且隨着架構使用變得更普遍),您應該檢查對象名稱和架構名稱,而不僅僅是對象名稱。在我的一些系統中,你的查詢會失敗,因爲可能有dbo.mytable和some_other_schema.mytable。另外,我不認爲你的意思是在你的第二個片段中引用「@tablename」。最後,要注意真正大的表,你可能會溢出INT - 這就是爲什麼sp_spaceused,例如,在幾種情況下轉換爲BIGINT。 –