2

在我们的环境中,一个过程需要很长时间才能执行。我已经检查了程序,以下是摘要-

  1. 该过程仅包含选择块(大约 24 个)。在每次选择之前,我们都会检查数据是否存在。如果是,请选择数据,否则执行其他操作。例如 :

    -- Select block 1 --
    IF EXISTS (SELECT 1 FROM table1 t1
              INNER JOIN table2 t2
              ON t1.col1=t2.col1
              WHERE t1.col2='someValue' AND t2.col2='someValue'
              )
    BEGIN
       SELECT t1.col1,t2.col2,t2.col3 FROM table1 t1
       INNER JOIN table2 t2
       ON t1.col1=t2.col1
       WHERE t1.col2='someValue' AND t2.col2='someValue'
    END
    ELSE
    BEGIN
      SELECT 'DEFAULT1', 'DEFAULT2', 'DEFAULT3'
    END
    
    
    -- Select block 2 --
    IF EXISTS (SELECT 1 FROM table1 t1
              INNER JOIN table2 t2
              ON t1.col1=t2.col1
              WHERE t1.col5='someValue' AND t2.col5='someValue'
              )
    BEGIN
       SELECT t1.col5,t2.col6,t2.col7 FROM table1 t1
       INNER JOIN table2 t2
       ON t1.col1=t2.col1
       WHERE t1.col5='someValue' AND t2.col5='someValue'
    END
    ELSE
    BEGIN
      SELECT 'DEFAULT1', 'DEFAULT2', 'DEFAULT3'
    END        
    

我得出的结论是,如果我们能以某种方式将 IF EXISTS 块中使用的查询合并到一个查询中,并为一些变量设置一些值,以便我们可以识别哪个条件返回 true,那么可以减少执行时间并提高性能。

我的想法正确吗?有什么选择吗?你能建议任何其他选择吗?

我们使用的是 Microsoft SQL Server 2005。

[已编辑:已添加] - 所有 select 语句都不会返回相同的列类型,它们是不同的。并且所有选择语句都是必需的。如果有 24 个 if 块,则过程应返回 24 个结果集。

[添加]

我想再问一件事,以下哪一项运行得更快-

  1. SELECT 1 FROM table1 t1 INNER JOIN table2 t2 ON t1.col1=t2.col1 WHERE t1.col2='someValue' AND t2.col2='someValue'
  2. SELECT COUNT(1) FROM table1 t1 INNER JOIN table2 t2 ON t1.col1=t2.col1 WHERE t1.col2='someValue' AND t2.col2='someValue'
  3. SELECT TOP 1 1 FROM table1 t1 INNER JOIN table2 t2 ON t1.col1=t2.col1 WHERE t1.col2='someValue' AND t2.col2='someValue'

谢谢。卡提克

4

3 回答 3

2

为了提高选择查询的性能...在 where 子句中使用的列上创建“索引”

就像你正在使用

WHERE t1.col2='someValue' AND t2.col2='someValue' 
WHERE t1.col5='someValue' AND t2.col5='someValue'

所以在col2col5上创建数据库索引


临时表 你可以使用临时表来存储结果。因为您使用相同的查询 24 次所以首先将以下查询的结果存储到临时表中(根据需要更正语法)

insert into temp_table (col2, col5)
SELECT col1, col5 FROM table1 t1
          INNER JOIN table2 t2
          ON t1.col1=t2.col1

现在使用临时表进行检查

-- Select block 1 --
IF EXISTS (SELECT 1 FROM temp_table
          WHERE t1.col2='someValue' AND t2.col2='someValue'
          )
BEGIN
   SELECT t1.col1,t2.col2,t2.col3 FROM table1 t1
   INNER JOIN table2 t2
   ON t1.col1=t2.col1
   WHERE t1.col2='someValue' AND t2.col2='someValue'
END

-- Select block 2 --
IF EXISTS (SELECT 1 FROM temp_table1
          WHERE t1.col5='someValue' AND t2.col5='someValue'
          )
BEGIN
   SELECT t1.col5,t2.col6,t2.col7 FROM table1 t1
   INNER JOIN table2 t2
   ON t1.col1=t2.col1
   WHERE t1.col5='someValue' AND t2.col5='someValue'
END
于 2013-10-01T10:25:12.927 回答
0

您可以将查询结果外连接到一行默认值,然后在查询结果为空时回退到默认值:

SELECT
  col1 = COALESCE(query.col1, defaults.col1),
  col2 = COALESCE(query.col2, defaults.col2),
  col3 = COALESCE(query.col3, defaults.col3)
FROM
  (SELECT 'DEFAULT1', 'DEFAULT2', 'DEFAULT3') AS defaults (col1, col2, col3)
LEFT JOIN
  (
    SELECT t1.col1, t2.col2, t2.col3
    FROM table1 t1
    INNER JOIN table2 t2
    ON t1.col1=t2.col1
    WHERE t1.col2='someValue' AND t2.col2='someValue'
  ) query
  ON 1=1  -- i.e. join all the rows unconditionally
;

如果子查询实际上可能返回 NULL 并且不能用默认值替换,那么该方法可能不适合您。在这种情况下,让子查询返回一个标志列(任何值)。如果该列在最终查询中计算为 NULL,那只能意味着子查询没有返回行。您可以在这样的 CASE 表达式中使用该事实:

SELECT
  col1 = CASE WHEN query.HasRows IS NULL THEN defaults.col1 ELSE query.col2 END,
  col2 = CASE WHEN query.HasRows IS NULL THEN defaults.col2 ELSE query.col2 END,
  col3 = CASE WHEN query.HasRows IS NULL THEN defaults.col3 ELSE query.col2 END
FROM
  (SELECT 'DEFAULT1', 'DEFAULT2', 'DEFAULT3') AS defaults (col1, col2, col3)
LEFT JOIN
  (
    SELECT HasRows = 1, t1.col1, t2.col2, t2.col3
    FROM table1 t1
    INNER JOIN table2 t2
    ON t1.col1=t2.col1
    WHERE t1.col2='someValue' AND t2.col2='someValue'
  ) query
  ON 1=1
;
于 2013-10-02T14:41:33.967 回答
0

当前的结构不是很有效——你必须有效地执行每个“if”语句(这将是昂贵的),然后如果“if”返回 true,则重复相同的 where 子句(昂贵的位)。而你这样做了 24 次。最坏的情况(所有查询都返回数据),您将查询时间加倍。

您说您已经检查了索引 - 鉴于每个查询似乎略有不同,因此值得仔细检查。

显而易见的事情是重构应用程序以执行 24 条选择语句,并处理有时它们不返回任何数据的事实。这是一个相当大的重构,我假设你已经考虑过......

如果你不能做到这一点,考虑一个不那么雄心勃勃(虽然更糟糕)的重构。与其检查数据是否存在,并返回它或等效的默认结果集,不如将其编写为联合:

   SELECT t1.col1,t2.col2,t2.col3 FROM table1 t1
   INNER JOIN table2 t2
   ON t1.col1=t2.col1
   WHERE t1.col2='someValue' AND t2.col2='someValue'
   UNION  
   SELECT 'DEFAULT1', 'DEFAULT2', 'DEFAULT3'

这减少了您点击 where 子句的次数,但意味着您的客户端应用程序必须过滤掉“默认”数据。

为了回答您的最后一个问题,我将通过查询优化器运行它并查看执行计划 - 但我想第一个版本是最快的 - 查询可以在找到与 where 匹配的第一条记录后立即完成标准。第二个版本必须找到所有匹配的记录并计算它们;最终版本必须找到所有记录并选择第一个。

于 2013-10-01T11:10:12.643 回答