我正在使用 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只在字符串被硬编码时选择索引,并在从另一个表中选择时选择表扫描。有人请给我一个线索,并提前感谢你。
答案 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标志)以及实际的表定义和存储过程源更有可能产生有用的答案。