Postgres选择执行顺序不正确

时间:2015-12-03 20:47:29

标签: sql postgresql execution

以下查询在Postgres 9.4.5中不起作用。

SELECT * FROM (
   SELECT M.NAME, M.VALUE AS V
     FROM METRICS AS M, METRICATTRIBUTES AS A
    WHERE M.NAME=A.NAME AND A.ISSTRING='FALSE'
    ) AS S1
 WHERE CAST(S1.V AS NUMERIC)<0

我收到如下错误:

invalid input syntax for type numeric: "astringvalue"

请继续阅读,看看为什么我的查询过于复杂。

METRICS是一个度量,值对的表。值存储为字符串,VALUE字段的某些值实际上是字符串。 METRICATTRIBUTES表标识可能具有字符串值的度量标准名称。我从METRICS表的分析中填充了METRICATTRIBUTES表。

要检查,我跑了......

SELECT * FROM (
    SELECT M.NAME, M.VALUE AS V
      FROM METRICS AS M, METRICATTRIBUTES AS A
     WHERE M.NAME=A.NAME AND A.ISSTRING='FALSE'
    ) AS S1
 WHERE S1.V LIKE 'a%'

这不会返回任何值(就像我期望的那样)。错误似乎在执行计划中。这看起来像这样(对不起,我不得不胖手指)

1 -> HAS JOIN 
2    HASH COND: ((M.NAME::TEXT=(A.NAME)::TEXT))
3       SEQ SCAN ON METRICS M
4       FILTER: ((VALUE)::NUMERIC<0::NUMERIC)
5   -> HASH 
6     -> Seq Scan on METRICATTRIBUTES A
7        Filter: (NOT ISSTRING)

我不是这方面的专家(只有1周的Postgres经验)但看起来Postgres在应用连接条件(第2行)之前尝试应用强制转换(第4行)。通过这样做,它将尝试将强制转换应用于无效的字符串值,这正是我想要避免的!

使用显式连接写这个没有任何区别。将它作为单个选择语句编写是我的第一次尝试,从不期待这种类型的问题。这也行不通。

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

正如您从计划中看到的那样,表格METRICS正在全面扫描(Seq Scan)并根据您的条件进行过滤:CAST(S1.V AS NUMERIC)<0 - 加入并不限制范围。

显然,您有一些行,其中包含METRICS.VALUE中的非数字数据。 检查表格中是否有这样的行:

SELECT * FROM METRICS
 WHERE NOT VALUE ~ '^([0-9].,e)*$'

请注意,很难用正则表达式捕获所有可能的组合,因此请查看以下相关问题:isnumeric() with PostgreSQL

列的名称VALUE不合适,因为这个词is a reserved one

编辑:如果您完全确定,那么连接的表格会生成所需的VALUE - s,而不是使用CTEs,它们在PostgreSQL中具有优化围栏功能:

WITH S1 AS (
    SELECT M.NAME, M.VALUE AS V
      FROM METRICS AS M
      JOIN METRICATTRIBUTES AS A USING (NAME)
     WHERE A.ISSTRING='FALSE'
)
SELECT *
  FROM S1
 WHERE CAST(S1.V AS NUMERIC)<0;