2009-11-24 35 views
0

我有一個MS SQL 2008數據庫,用於存儲創建加權無向圖的數據。數據被存儲在表中具有以下結構:帶有動態表名或重新設計的SQL語句?

[id1] [int] NOT NULL, 
[id2] [int] NOT NULL, 
[weight] [float] NOT NULL 

其中[ID1]和[ID2]表示兩個連接節點和[重量]連接這些節點的邊的權重。

有幾種不同的算法,從一些基礎數據創建圖形。對於每種算法,我想將圖形數據存儲在單獨的表中。這些表都具有相同的結構(如上所示)並使用指定的前綴(類似性ALB,文章類似性,類似性,類別...),因此我可以將它們識別爲圖表。

客戶端程序可以選擇哪個表格(即通過哪個算法創建圖表)用於進一步的操作。

訪問數據由存儲過程完成。因爲我有不同的表,我需要使用一個變量的tablename例如爲:

SELECT id1, id2, weight FROM @tableName 

這不起作用,因爲SQL不支持在聲明變量表名。我已經在網上搜索和對這個問題的所有解決方案使用動態SQL EXEC()語句如:

EXEC('SELECT id1, id2, weight FROM ' + @tableName) 

因爲其中大部分人提到,這使得容易出現SQL注入,我想它的聲明避免。一個簡單的重新設計的想法是將所有不同的圖表放在一張表中,並添加一列來標識不同的圖表。

[graphId] [int] NOT NULL, 
[id1] [int] NOT NULL, 
[id2] [int] NOT NULL, 
[weight] [float] NOT NULL 

我對這個解決方案的問題是,根據使用的算法(高達500萬條目),圖形可能非常大。我需要通過索引表(id1,id2)和(id2,id1)。現在把它們放在一張大桌子裏會讓表格變得更加龐大(並且要求更慢)。由於活躍的指標,添加新圖表會導致性能不佳。刪除圖表不能被TRUNCATE做了,我會需要使用

DELETE * FROM myTable WHERE [email protected] 

與大表表現得非常糟糕,並創建一個非常大的日誌文件(在圖中是足夠大的,這將超過我的磁盤空間) 。所以我想保留每張圖的獨立表。

任何建議如何通過查找參數化表名或重新設計數據庫結構的方法來解決這些問題,同時避免上述問題?

回答

1

通過將@tableName與現有表的名稱進行比較,可以輕鬆避免SQL注入。如果它不是其中之一,那就是糟糕的輸入。 (強制XKCD參考:也就是說,除非你有一個名爲"bobby'; drop table students;"表)

不管怎樣,關於你的性能問題,使用分區表(因爲SQLServer的2005),你可以像有幾個表相同的優點,但沒有需要動態SQL。

+0

我喜歡錶n最大限度地檢查,認爲我會這樣。我看了一下分區表 - 一個問題是我不能使用截斷來刪除整個圖表(就像IronGoofy提到的那樣)。另外,我將看看如何使用sp_executesql,因爲它支持參數替換和執行計劃(以供重用)。 – Aaginor 2009-11-24 12:51:02

+0

在Oracle中,可以截斷分區表中的單個分區(ALTER TABLE foo TRUNCATE PARTITION bar;)。在SQL-Server中,你必須將數據從分區移動到一個新的表格中,然後你可以放下......怪異的...... – 2009-11-24 13:28:30

0

Partioned Table可能是您的問題的答案。我有另一種想法,那就是「周圍的其他方法」:

  • 每個圖都有它自己的表(所以你仍然可以截斷表)
  • 定義視圖(與結構化你的重新提到表)作爲一個聯盟所有在所有圖表

我不知道在這個視圖等選擇的性能,但它可能會給你你在找什麼。我很感興趣的是結果,如果嘗試了這一點..

+0

我猜想,UNION表格首先出現了(因此性能更差),但我會檢查一下。 – Aaginor 2009-11-24 12:53:19

+0

我檢查了一下:對視圖的第一個查詢花了大約需要查詢所有表的時間。對該查詢的任何重複調用花費的時間幾乎與需要通過單個表進行查詢的時間相同。 (我用UNION超過5張桌子來看)所以這只是第一次打電話,但這仍然不好,我認爲 – Aaginor 2009-11-24 13:30:42

1

也許我不明白一切,但:

CREATE PROCEDURE dbo.GetMyData (
    @TableName AS varchar(50) 
    ) 
AS 
BEGIN 
    IF @TableName = 'Table_1' 
     BEGIN 
      SELECT id1 
        ,id2 
        ,[weight] 
      FROM dbo.Table_1 
     END 

    IF @TableName = 'Table_2' 
     BEGIN 
      SELECT id1 
        ,id2 
        ,[weight] 
      FROM dbo.Table_2 
     END 
END 

然後:

EXEC dbo.GetMyData @TableName = 'Table_1' 

一個不同的技術涉及例如:動態使用同義詞,例如:

DECLARE @TableName varchar(50) 
SET @TableName = 'Table_1' 

-- drop synonym if it exists 
IF object_id('dbo.MyCurrentTable', 'SN') IS NOT NULL 
    DROP SYNONYM MyCurrentTable ; 

-- create synonym for the current table 
IF @TableName = 'Table_1' 
    CREATE SYNONYM dbo.MyCurrentTable FOR dbo.Table_1 ; 

IF @TableName = 'Table_2' 
    CREATE SYNONYM dbo.MyCurrentTable FOR dbo.Table_2 ; 

-- use synonym 
SELECT id1, id2, [weight] 
FROM dbo.MyCurrentTable 
+0

我已經使用IF(@ Table ='mytable1')... ELSE IF(.. )在我的存儲過程中構建,但我想擺脫它。每當我添加,重命名或刪除一個新表,我需要更新所有我的SP。但這個同義詞看起來很有趣!是否有可能創建一個程序或函數來創建同義詞,然後從我存儲的特效中調用,以便他們可以使用同義詞?然後,我只需要在添加/更新/刪除表格時更新ONE proc/function! – Aaginor 2009-11-25 10:39:20

+0

是的同義詞是一個db對象,它是另一個db對象的替代名稱。 – 2009-11-25 11:57:23

+0

我已經實現了同義詞對象設置存儲過程,它工作得很好......直到我開始同時訪問SP。看起來我需要爲每個過程調用定義一個特殊的同義詞。 – Aaginor 2009-12-10 16:34:06