【问题标题】:Stored procedure in SQL that checks if index not exist then createSQL中的存储过程检查索引是否存在然后创建
【发布时间】:2021-10-05 02:10:35
【问题描述】:

当我执行它时,我的 SQL 脚本运行良好。

现在的问题是,当我检查表索引时,此脚本不会创建索引。

下面是脚本

CREATE PROCEDURE test 
     @TableName nvarchar(128)
AS 
BEGIN
    DECLARE @sql nvarchar(max)

    SET @Sql  = N'IF NOT EXISTS (SELECT name FROM sys.indexes WHERE name = Index_type) 
                     CREATE UNIQUE CLUSTERED INDEX Index_type 
                         ON ' + QUOTENAME(@TableName) + N'(CustomerId) ON "PRIMARY"';
END

EXECUTE test customer 

【问题讨论】:

  • 除了问题@GordonLinoff 提到对sys.indexes 的任何检查也应该检查object_id - 索引名称不必在对象之间是唯一的
  • 尽管忘记了所有这些,这个过程实际上有什么用途?它只适用于包含 CustomerID 列并且该列应该是集群索引的表,并且这感觉不需要动态完成,它应该在创建时完成一次表,然后再也没做过。
  • 是的,但是为什么需要动态完成呢?这意味着您需要动态检查索引是否存在,而从逻辑上讲,您只需要在创建表的同时创建一次聚集索引,因此这应该在您的创建表脚本中,而不是在调用一些非常不稳定的动态 SQL
  • 听起来我们这里有一个xy problem
  • 如果你只需要在这15个表上创建一次这些索引,它仍然不需要存储过程,只需编写15个创建索引脚本。大约需要 10 分钟,然后它就完成了,你再也不用担心它了。如果您将来要创建更多表,只需在创建表的同时创建索引。如果您要删除聚集索引,然后简单地禁用执行此操作的任何进程,这是一个糟糕的主意

标签: sql sql-server database stored-procedures azure-sql-database


【解决方案1】:

这是可能的(链接到答案末尾的非常简单的演示,但这并不能说明所有情况),但我真的不会动态地这样做。如果您要动态创建任何索引,这有点代码味道,更不用说集群索引了。

问题是,您可以确定一个表是否具有 CustomerID 列,是否包含唯一值,以及是否已经没有聚集索引,但这些都不能告诉您聚集索引是否合适。考虑下表

CREATE TABLE Orders
(
    OrderID INT IDENTITY(1, 1) NOT NULL,
    CustomerID INT NOT NULL,
    OrderDate DATE NOT NULL,
    ....
);

这没有聚集索引,有一个名为 CustomerID 的表,如果 CustomerID 为空或只有几个订单,则 CustomerID 可能是唯一的,因此在 CustomerID 上创建聚集索引的候选对象也是如此。但是 CustomerID 显然不是这里合适的聚类键。世界上没有脚本可以告诉您您打算如何使用您的表格,您可以使用最佳设计实践来尝试解决它,甚至是标准约定(如列序数),但没有任何事情会永远完美地做到这一点。

更好的方法是一次性完成此任务,您可以使用 customerID 列识别所有表,甚至给自己一个模板创建索引脚本,如下所示:

SELECT t.name,
        CreateIndexScript = CONCAT('CREATE UNIQUE CLUSTERED INDEX UQ_', 
                                    NULLIF(s.name, 'dbo') + '_', t.name, '_CustomerID ON ',
                                    QUOTENAME(s.name), '.', QUOTENAME(t.name), ' (CustomerID);')
FROM    sys.tables AS t
        INNER JOIN sys.schemas AS s
            ON s.schema_id = t.schema_id
WHERE   EXISTS (SELECT 1 FROM sys.columns AS c WHERE c.object_id = t.object_id AND c.name = 'CustomerID')
AND     NOT EXISTS (SELECT 1 FROM sys.indexes AS i WHERE i.object_id = t.object_id AND i.type = 1)

然后,您可以查看此脚本抛出的每个表以查看在 CustomerID 上创建聚集索引是否合适,然后手动运行脚本。索引一旦创建就不应被删除,因此您不必担心它会定期运行。

Demo on DB<>Fiddle

【讨论】:

  • 谢谢 garethd 。但是我有不同的表名,每个表都有不同的列名。并非所有表都有 CUSTOMER_ID 列。实际上我需要检查每个表是否存在索引(我不知道它存在于哪一列)。如果它不存在,那么我需要在任何列上创建一个索引。
  • 我选择动态 sql 的原因是可能有 200 个表。我不能为 200 个表硬编码它。所以我想编写一个从表列表中动态选择表名的过程。然后它检查它的索引,。如果它不存在,则创建它。所以你看到我会动态获取表名,我还需要动态获取列名
  • 那么给定一个特定的表名,你怎么知道哪一列应该是集群键,以便你可以在它上面动态创建索引?你怎么知道它应该在集群键中只有一列?多列完全有可能构成集群键,尤其是在联结表的情况下。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-27
  • 2023-03-16
  • 1970-01-01
  • 2011-01-05
  • 1970-01-01
  • 2019-10-07
  • 1970-01-01
相关资源
最近更新 更多