1

在 Sql Server 2012 SP3 v.11.0.6020.0 (X64) 中,我有一个存储过程,它测试全局临时表(##MyTable例如)的存在并创建它 - 当然如果没有找到。

IF OBJECT_ID ( 'tempdb..##MyTable' ) IS NULL
    CREATE TABLE ##MyTable
    (
        Key1 smallint
      , Key2 nvarchar(16)
      , Value1 char(3)
    );

在该过程的稍后部分,它会测试表是否有行,并在必要时填充它。

IF NOT EXISTS ( SELECT * FROM ##MyTable )
BEGIN
    INSERT INTO ##MyTable
    SELECT Key1, Key2, Value1
    FROM SourceTable
    WHERE ...

    CREATE NONCLUSTERED INDEX IX_MyTable ON ##MyTable ( [Key1], [Key2] ); 
END

我确信 Key1 和 Key2 是唯一的,因为它们是源表上的主键。

然后,无论哪种情况(表已经存在或不存在),存储过程都会查询表。不用说,sp 逻辑比这复杂得多。

该表包含来自 7 个不同来源的客户数据;通常,插入近 100 万行需要几秒钟。从理论上讲,所有 INSERT INTO ##MyTable 都不可能插入 0(零)行。

存储过程由应用程序调用:该应用程序通常在早上启动并在晚上关闭。

从理论上讲,可能存在冲突,用户尝试插入数据并创建索引,而另一个用户已经在做同样的事情。但它不太可能总是发生在同一个用户身上。如果该用户在几分钟后再次尝试(表和索引已经存在),这应该是不可能的。

这对所有用户(接近 100 个)都适用,但对一个特定的用户来说,他会不断收到错误:The operation failed because an index or statistics with name 'IX_MyTable' already exists on table ##MyTable.

除了我已经在考虑使全局临时表成为常规表这一事实之外,任何人都可以向我解释这种行为吗?

提前感谢任何会提供帮助的人!

4

3 回答 3

3

在这些情况下,您会遇到这种行为:

  1. 您创建表。它是空的。
  2. 查询已insert运行,​​但不插入任何行。
  3. 索引已创建。

在下一次运行时,您将有一个空表并insert再次尝试。

这很容易解决。只需在创建索引之前使用try/块或测试以查看索引是否存在。catch或者,更好的是,在创建表时创建索引。除非您插入大量数据,否则开销应该不会太差。

于 2017-03-06T12:33:54.230 回答
1

如果您在表创建块本身中移动您的 Create Index 语句会更好..

IF OBJECT_ID ( 'tempdb..##MyTable' ) IS NULL
BEGIN
    CREATE TABLE ##MyTable
    (
        Key1 smallint
      , Key2 nvarchar(16)
      , Value1 char(3)
    );
    CREATE NONCLUSTERED INDEX IX_MyTable ON ##MyTable ( [Key1], [Key2] ); 
END
于 2017-03-06T13:10:53.313 回答
1

错误说明,您必须在创建表时创建索引,当它已经存在时您不能创建索引

IF OBJECT_ID ( 'tempdb..##MyTable' ) IS NULL
Begin
CREATE TABLE ##MyTable
(
    Key1 smallint
  , Key2 nvarchar(16)
  , Value1 char(3)
);
CREATE NONCLUSTERED INDEX IX_MyTable ON ##MyTable ( [Key1], [Key2] );
END 

在您的存储过程中,当表为空时,您正在条件内创建索引,因此每次从表中删除所有数据时,它都会尝试创建索引。

于 2017-03-06T12:55:19.393 回答