2

我正在使用Sybase 12.5.3 (ASE);我是 Sybase 的新手,尽管我已经广泛使用 MSSQL。我遇到了一个存储过程非常慢的场景。我已经将问题追溯到一个相对较大的表的单个 SELECT stmt。修改该语句显着提高了过程的性能(并且恢复它会大大减慢它;即,SELECT stmt 绝对是罪魁祸首)。

-- Sybase optimizes and uses multi-column index... fast!<br>
SELECT ID,status,dateTime
FROM myTable
WHERE status in ('NEW','SENT')
ORDER BY ID

-- Sybase does not use index and does very slow table scan<br>
SELECT ID,status,dateTime
FROM myTable
WHERE status in (select status from allowableStatusValues)
ORDER BY ID

上面的代码是实际代码的改编/简化版本。请注意,我已经尝试过重新编译过程、更新统计信息等。

我不知道为什么 Sybase ASE 只会在字符串被硬编码时选择索引,而在从另一个表中选择时选择表扫描。有人请给我一个线索,并提前谢谢你。

4

6 回答 6

2

索引提示可以解决它,但可能不是解决方案。

首先,我想知道allowableStatusValues.status 上是否有索引,如果有,那么sybase 就会有统计信息,并且会对其中的值数量有一个很好的了解。如果不是,那么优化器可能不会很好地知道 Status 可以采用多少不同的值。然后必须假设您将从 myTable 中提取几乎所有行,而最好的方法是表扫描(如果没有覆盖索引)。

现在您不必添加索引来获取列的统计信息,但这可能是最好的方法。

如果您确实有关于 allowableStatusValues.status 的索引,那么我想知道您的统计数据有多好。获取一份sp__optdiag的副本。您可能还需要调整“直方图调整因子”和“直方图步数”的值,从默认值略微增加这些值将为您提供更详细的统计信息,这总是有助于优化器。

于 2010-03-24T13:28:20.903 回答
2

1.这里的问题是糟糕的编码。在您的版本中,糟糕的代码和糟糕的表格设计是优化器做出错误决策的主要原因(98%)(两者并存,我还没有弄清楚各自的比例)。两个都:

    WHERE status IN ('NEW','SENT')

    WHERE status IN (SELECT status FROM allowableStatusValues)

是不合标准的,因为在这两种情况下,它们都会导致 ASE 为括号之间的内容创建一个工作表,这很容易避免(并且避免了所有后续问题)。没有关于工作表的统计信息的可能性,因为缺少 t.status 或 s.status 的统计信息(AdamH 在这一点上是正确的),它正确地选择了表扫描。

子查询有它们的位置,但永远不能替代纯(表相关的)连接。更正如下:

    WHERE status = "NEW" OR status = "SENT"

    FROM  myTable t,
          allowableStatusValues s
    WHERE t.status = s.status

2.声明

| 现在您不必添加索引来获取列的统计信息,但这可能是最好的方法。

是不正确的。切勿创建您不会使用的索引。如果您想更新列的统计信息,只需

    UPDATE STATISTICS myTable (status)

3. 重要的是要确保您拥有 (a) 所有索引列和 (b) 所有连接列的当前统计信息。

4.是的,在每个打算发布的代码段上都没有 SHOWPLAN 的替代品,对于任何性能有问题的代码来说更是如此。您也可以SET NOEXEC ON,以避免执行,例如。对于大型结果集。

于 2010-10-23T09:42:45.037 回答
1

如果您将子查询替换为连接,它是否仍会进行表扫描:

SELECT m.ID,m.status,m.dateTime 
FROM myTable m
JOIN allowableStatusValues a on m.status = a.status
ORDER BY ID 
于 2010-03-24T13:42:23.233 回答
0

我强烈建议让 Sybase 向您展示每个查询的执行计划,而不是依赖于对查询运行时间的实验观察,例如:

SET showplan ON
GO

-- query/procedure call goes here
SELECT id, status, datetime
FROM myTable
WHERE status IN('NEW','SENT')
ORDER BY id
GO

SET showplan OFF
GO

使用SET showplan ON,Sybase 会为其执行的每条语句生成执行计划。这些对于帮助确定查询未使用适当索引的位置非常宝贵。对于 Sybase 中的存储过程,整个过程的执行计划是在存储过程编译后第一次执行时生成的。

如果您发布每个查询的计划,我们可能会更清楚地了解问题。

于 2010-03-23T17:05:21.710 回答
0

令人惊讶的是,使用索引提示可以解决问题(请参见下面的(index myIndexName)行 - 下面是重写/简化的代码:

-- using INDEX HINT
SELECT ID,status,dateTime 
FROM myTable (index myIndexName)
WHERE status in (select status from allowableStatusValues) 
ORDER BY ID 

奇怪的是我必须使用这种技术来避免表扫描,但是你去吧。

于 2010-03-23T19:18:41.947 回答
0

Garrett,通过仅显示简化的代码,您可能已经准确地删除了能够阐明问题根源的信息。

我的第一个猜测是allowableStatusValues.status 和myTable.status 之间的类型不匹配。然而,这不是唯一的可能性。正如 Nineside 所说,完整的查询计划(使用 showplan 和 fmtonly 标志),以及实际的表定义和存储过程源,更有可能产生有用的答案。

于 2010-03-23T21:50:46.123 回答