sybase - 除非字符串是硬编码的,否则无法使用索引

时间:2010-03-23 16:44:47

标签: tsql database-performance sybase-ase

我正在使用 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只在字符串被硬编码时选择索引,并在从另一个表中选择时选择表扫描。有人请给我一个线索,并提前感谢你。

6 个答案:

答案 0 :(得分:2)

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

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

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

如果你在allowableStatusValues.status上有索引,那么我想知道你的统计数据有多好。给自己一份sp__optdiag的副本。您可能还需要调整“直方图调整因子”和“直方图步数”的值,从默认值中稍微增加这些值将为您提供更详细的统计信息,这些统计信息始终有助于优化器。

答案 1 :(得分: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,以避免执行,例如。对于大型结果集。

答案 2 :(得分:1)

如果使用连接替换子查询,它是否仍然执行表扫描:

SELECT m.ID,m.status,m.dateTime 
FROM myTable m
JOIN allowableStatusValues a on m.status = a.status
ORDER BY ID 

答案 3 :(得分: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中的存储过程,在编译后首次执行存储过程时会生成整个过程的执行计划。

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

答案 4 :(得分:0)

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

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

很奇怪我 使用这种技术来避免表扫描,但是你可以去。

答案 5 :(得分:0)

Garrett,只显示简化代码,您可能已经完全删除了可以解决问题根源的信息。

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