1

我在 Hypersonic DB (HSQLDB) 中运行以下查询:

SELECT (CASE foo WHEN 'a' THEN 'bar' WHEN 'b' THEN 'biz' ....
        ELSE 'fin' END ) FROM MyTable LIMIT 1

当“WHEN”子句的数量超过大约 1000 条时,我会StackOverflowErrororg.hsqldb.jdbc.Util.sqlException().

这是真正奇怪的部分:我尝试CASE用例如 100 个 WHEN 子句后跟ELSE ( CASE foo WHEN ... ) END. 但是即使进行了这种重写,我也会得到完全相同的行为!

我在 HSQLDB 手册中没有看到任何对 1000 限制或任何其他内容的引用。帮助!

4

3 回答 3

2

CASE你永远不应该在声明中接近 1000 个术语。在此之前很久,您应该将其他值放入单独的表中并通过加入来选择它们。

INSERT INTO MappingTable (foo, string) VALUES
  ('a', 'bar'), ('b', 'biz'), ...

SELECT COALESCE(m.string, 'fin')
FROM MyTable t LEFT OUTER JOIN MappingTable m USING (foo)
LIMIT 1;

Java API 说 StackOverflowError:

当由于应用程序递归太深而发生堆栈溢出时引发。

所以我猜想,当 HSQLDB 解析一个CASE表达式时,每个WHEN术语都会向运行时堆栈添加另一层(实际上每个可能有几层WHEN)。

如果您有一个包含 1,000 级嵌套括号的算术表达式,您可能会得到类似的 StackOverflowError。

1,000 的限制可能是可变的,具体取决于 Java VM 的实现、Java 版本、您运行的平台、可用内存量等。他们可能不会在 HSQLDB 文档中记录它,因为它是特定于平台的限制,而不是内置在 HSQLDB 中的东西。

于 2009-01-12T22:27:23.267 回答
1

完全消除 CASE 语句。

使用这 1000 个值创建一个表,然后对该表进行内部连接。

于 2009-01-12T22:28:01.287 回答
1

正如比尔所说,鉴于明显的 HSQL 解析器设计,不可能消除限制。

在减轻限制方面(即让自己达到 1000 个开关,只需将限制推到……超过 1000 个),您有两个选择。

  1. 运行应用程序时增加 VM 中的堆栈大小。如果您使用的是 Sun 的 Hotspot VM,您应该能够传递例如 -XX:ThreadStackSize=1024 以使用每个线程 1MB 的堆栈,而不是默认的 512K。这可能会让您获得更大的递归深度。
  2. 您可以在构造函数 Thread(ThreadGroup, Runnable, String, long) 创建的 Thread 中运行您的工作,其中最后一个参数是请求的堆栈大小。这可能有效,也可能无效;如果您阅读 Javadoc,这是一个建议——非常欢迎 VM 忽略此请求。不确定 Hotspot 的具体用途,但它可能会有所帮助。
于 2009-01-12T23:26:19.653 回答