代码之家  ›  专栏  ›  技术社区  ›  Cheburek

SQL Server 2008执行计划问题

  •  3
  • Cheburek  · 技术社区  · 16 年前

    我有一个问题要问sql专家。

    有两张结构几乎相同的表。

    如何以最佳方式做到这一点?

    请不要建议将这些表格合并成一个表格-这是不合适的。

    Select *
    FROM
        String s
        JOIN (
            SELECT id
                ,TypeCode
                ,ProdNo         
                    FROM Table1
            WHERE @param = 1 AND TypeCode= 'INV'
    
            UNION
    
            SELECT id
                ,TypeCode
                ,ProdNo
            FROM Table2
            WHERE @param = 2 AND TypeCode= 'INV'
    
        ) m ON m.Id = s.Id
    WHERE s.Id = 256
    

    但当我查看执行计划时,我很惊讶,因为它以并行线程的形式从两个表中获取数据,并且只在这之后通过@param value进行过滤。

    我认为过滤将在第一阶段进行,并从单个表中收集数据。

    有没有一种方法可以使select只从一个表中进行,而不必将查询拆分为两个查询并使用IF运算符?

    谢谢

    5 回复  |  直到 15 年前
        1
  •  4
  •   KM.    16 年前

    你真的需要看看这个 Dynamic Search Conditions in T-SQL by Erland Sommarskog . 你不应该担心重复代码,这不是什么家庭作业。只是担心执行计划使用索引。使SQL代码“漂亮”时,唯一要考虑的是缩进;在这种情况下,任何其他更改都可能导致查询计划变慢。我在超慢查询中看到了对超快查询结果的细微更改。去速度(索引使用)和复制代码的需要。另请参见: The Curse and Blessings of Dynamic SQL

    OPTION(RECOMPILE) 这种行为基本上是在运行时计算@Local\u Variables值并相应地重新编译查询。在您的情况下,这将导致在编译它们时消除一半的联合。

        2
  •  4
  •   Chris Diver    16 年前

    你能用一个简单的IF语句吗?

    IF @Param = 1 
      BEGIN
        EXEC SQL
      END
    ELSE IF @Param = 2
      BEGIN
        EXEC SQL
      END 
    ELSE
      RAISERROR('Invalid Parameter', 16, 1)
    

    或者,您也可以动态构建查询,并使用sp\u executesql存储过程执行它。

    DECLARE @Sql NVARCHAR(100)
    
    SET @Sql = N'SELECT * FROM ('
    
    IF @Param = 1
      SET @Sql = @Sql + N'SELECT 1 a, 2 b, 3 c'
    ELSE IF @param = 2
      SET @Sql = @Sql + N'SELECT 4 a, 5 b, 6 c'
    ELSE
      RAISERROR('Invalid Parameter', 16, 1)
    
    SET @Sql = @Sql + ') tbl'
    EXEC sp_executesql @sql
    
        3
  •  1
  •   Chris Bednarski    16 年前

    UNION UNION ALL

    Select * 
    FROM 
        String s 
        JOIN ( 
            SELECT id 
                ,TypeCode 
                ,ProdNo          
                    FROM Table1 
            WHERE @param = 1 AND TypeCode= 'INV' AND id = 256
    
            UNION ALL
    
            SELECT id 
                ,TypeCode 
                ,ProdNo 
            FROM Table2 
            WHERE @param = 2 AND TypeCode= 'INV' AND id = 256
    
        ) m ON m.Id = s.Id 
    WHERE s.Id = 256 
    
        4
  •  0
  •   Callie J    16 年前

    SQL Server并没有那么聪明—在编写查询时,您应该只确保发送最少的SQL来获取所需的数据(而不发送多余的语句),而且尽可能提供最多的信息(通过过滤器),以便向查询优化者提供尽可能多的有关数据的提示。如您所见,它将执行您发送给它的所有SQL。

    DECLARE @sql NVARCHAR(1000)
    
    SET @sql = 'SELECT id, TypeCode, ProdCode'
    IF @param = 1
       SET @sql = @sql + ' FROM table1'
    IF @param = 2
       SET @sql = @sql + ' FROM table2'
    SET @sql = @sql + ' WHERE TypeCode = ''INV'''
    
    EXECUTE sp_ExecuteSQL @sql
    

    请注意,如果您要将其归纳为一些更复杂的关于小Bobby表的内容:可以滥用sp\u ExecuteSQL并打开漏洞,但如果使用正确(使用参数化动态SQL),它就和存储过程一样好。

        5
  •  0
  •   potatopeelings    16 年前

    如果可以创建一个tDUMMY表( 具有

    Select 
        * 
    FROM 
        String s 
        JOIN ( 
            SELECT 
                 id, TypeCode, ProdNo
            FROM 
                 tDUMMY INNER JOIN Table1 ON TypeCode= 'INV'
            WHERE
                 @param = 1
    
     UNION ALL
    
            SELECT 
                 id, TypeCode, ProdNo
            FROM 
                 tDUMMY INNER JOIN Table2 ON TypeCode= 'INV'
            WHERE
                 @param = 2
         ) m ON m.Id = s.Id 
    WHERE s.Id = 256
    

    理论上 查询优化器应该首先过滤tDUMMY表,然后尝试连接。因此,如果@param=1,第二个查询应该更快地发出(它将再次检查1行tDUMMY,但是 不应该 检查表2)

    注意-我还将其全部合并(但不会产生太大影响),因为一方始终不会返回任何行。