在我们的环境中,一个程序需要很长时间才能执行。我已检查过程,以下是摘要 -
该过程仅包含select块(大约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个块,则程序应该返回24个结果集。
[补充]
我想再问一个问题,下面哪一项运行得更快 -
感谢。 Kartic
答案 0 :(得分:2)
为了提高选择查询的性能...在where子句中使用的列上创建“索引”
就像你正在使用
WHERE t1.col2='someValue' AND t2.col2='someValue'
WHERE t1.col5='someValue' AND t2.col5='someValue'
所以在 col2 和 col5
上创建数据库索引临时表 您可以使用临时表来存储结果。由于您使用相同的查询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
答案 1 :(得分:0)
当前结构不是很有效 - 你实际上必须执行每个“if”语句(这将是昂贵的),然后如果“if”返回true,则重复相同的where子句(昂贵的位)。而你这样做了24次。最糟糕的情况(所有查询返回数据),您的查询时间加倍。
你说你已经检查了索引 - 假设每个查询看起来有些微妙的不同,那么值得仔细检查一下。
显而易见的是重构应用程序以执行24个select语句,并处理有时它们不返回任何数据的事实。这是一个相当大的重构,我假设你已经考虑过......
如果你不能这样做,可以考虑一个不那么雄心勃勃(虽然更糟糕)的重构。而不是检查数据是否存在,并返回它或等效的默认结果集,而是将其写为union:
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条件。第二个版本必须找到匹配并计算它们的所有记录;最终版本必须找到所有记录并选择第一个。
答案 2 :(得分: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
;