具有动态表名称或重新设计的SQL语句?

时间:2009-11-24 11:16:51

标签: sql-server stored-procedures

我有一个MS SQL 2008数据库,用于存储用于创建加权无向图的数据。数据存储在具有以下结构的表中:

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

其中[id1]和[id2]表示两个连接的节点,[weight]表示连接这些节点的边的权重。

有几种不同的算法,可以从一些基本数据创建图形。对于每种算法,我想将图形数据存储在单独的表中。这些表都具有相同的结构(如上所示)并使用指定的前缀(similarityALB,similaritybyArticle,similaritybyCategory,...),因此我可以将它们标识为图表。

客户端程序可以选择使用哪个表(即创建图表的算法)来进行进一步的操作。

通过存储过程访问数据。由于我有不同的表,我需要使用变量表名,例如:

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

我对此解决方案的问题是,根据使用的算法(最多5亿条目),图表可能非常大。我需要将表索引(id1,id2)和(id2,id1)。现在将它们全部放在一个大表中会使表格变得更大(并且要求更慢)。由于活跃的指标,添加新图表会导致性能不佳。 TRUNCATE无法再删除图形,我需要使用

DELETE * FROM myTable WHERE graphId=@Id

对大型表执行非常糟糕,并创建一个非常大的日志文件(当图表足够大时会超过我的磁盘空间)。所以我想为每个图保留独立的表格。

如何通过找到一种参数化表名或重新设计数据库结构同时避免上述问题来解决这些问题的建议?

3 个答案:

答案 0 :(得分:1)

在这种情况下,通过将@tableName与现有表的名称进行比较,可以轻松避免SQL注入。如果它不是其中之一,那就是糟糕的输入。 (强制性的xkcd参考:即,除非你有一个名为"bobby'; drop table students;"的表)

无论如何,关于性能问题,使用分区表(自SQLServer 2005以来),您可以拥有相同的优势,例如拥有多个表,但不需要动态SQL。

答案 1 :(得分: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

答案 2 :(得分:0)

Partioned Table可能是您问题的答案。我有另一个想法,那就是“反过来”:

  • 每个图表都有自己的表格(所以你仍然可以截断表格)
  • 将视图(使用您为重新定义的表提到的结构化)定义为所有图表的UNION ALL

我不知道这个视图上的select的性能等等,但它可能会给你你想要的东西。如果尝试这个,我会对结果感兴趣..