【问题标题】:Postgresql 9.3 Update Join Affects different number of rows than SelectPostgresql 9.3 Update Join 影响的行数与 Select 不同
【发布时间】:2016-02-17 09:38:08
【问题描述】:

我需要从我的数据库中选择一些特定的位置,然后更新它们。

尴尬的是,在单独执行Select 语句时,它使用了 90k 行。 但是在对同一个 Select 执行 Update 语句时,它影响 80k 行。

这会产生 90k 行。

SELECT
    "Extent2"."AppId",
    "Extent2"."DateCreated"
FROM
    "dbo"."Route" AS "Extent1"
    INNER JOIN
    "dbo"."Positions" AS "Extent2" ON
        "Extent1"."BoundAppId" = "Extent2"."AppId" AND
        "Extent2"."DateCreated" > "Extent1"."TimeStarted" AND
        "Extent2"."DateCreated" < "Extent1"."TimeFinished"
WHERE
    "Extent1"."TimeStarted" IS NOT NULL AND
    "Extent1"."TimeFinished" IS NOT NULL AND
    FALSE = "Extent1"."IsDeleted" AND
    "Extent1"."TimeFinished" < '2016-02-06'

这会影响 80k 行 (嵌套的 Select 是相同的)

UPDATE "dbo"."Positions" AS j0
SET "ArchiveUntil" = '2020-02-16'
FROM (
    SELECT
        "Extent2"."AppId",
        "Extent2"."DateCreated"
    FROM
        "dbo"."Route" AS "Extent1"
        INNER JOIN
        "dbo"."Positions" AS "Extent2" ON
            "Extent1"."BoundAppId" = "Extent2"."AppId" AND
            "Extent2"."DateCreated" > "Extent1"."TimeStarted" AND
            "Extent2"."DateCreated" < "Extent1"."TimeFinished"
    WHERE
        "Extent1"."TimeStarted" IS NOT NULL AND
        "Extent1"."TimeFinished" IS NOT NULL AND
        FALSE = "Extent1"."IsDeleted" AND
        "Extent1"."TimeFinished" < '2016-02-06'
) as j1
WHERE (j0."AppId" = j1."AppId" AND j0."DateCreated" = j1."DateCreated")

此 SQL 是从 EntityFramework.Extended Library Source Commit 分支(未与父级合并)生成的,但对我来说似乎很正常......

也许不是?

【问题讨论】:

  • 一般而言,您应该UPDATE 语句的FROM 子句中引用目标表。 SQL Server 需要这个,但是在 Postgres 中你不能这样做(除非你 do 打算自加入 - 我不认为你想要)。您的 SQL 生成器似乎不知道 Postgres 并生成了错误的 SQL。我认为你想要这样的东西:hastebin.com/osebabaqiz.sql
  • 是的,这是有道理的,考虑到我分叉的分支最初是从 SqlServer 语法到 Postgresql 的轻微修改。
  • 嗯,我收到错误:缺少表“Extend1”第 4 行的 FROM 子句条目:WHERE“Extend1”。“BoundAppId”= j0。“AppId”当将“Extend1”重命名为 J1 查询运行时但仍更新 80k 行

标签: sql postgresql postgresql-9.3


【解决方案1】:

您的查询没问题。我想您只是发现(AppId, DateCreated)Positions 中不是唯一的,或者其中一个值是NULL

您可以运行此查询来验证计数:

select appid, DateCreated, count(*)
from dbo.Positions
group by appid, DateCreated
having count(*) > 1;

也有可能某些值是NULL,您可以使用以下方法找到:

select p.*
from dbo.Positions p
where appid is null or DateCreated is null;

编辑:

哎呀。我怀疑以上是正确的想法,只是错误的列。尝试运行这个版本(你原来的聚合查询):

SELECT "Extent2"."AppId", "Extent2"."DateCreated", COUNT(*) as cnt
FROM
    "dbo"."Route" AS "Extent1"
    INNER JOIN
    "dbo"."Positions" AS "Extent2" ON
        "Extent1"."BoundAppId" = "Extent2"."AppId" AND
        "Extent2"."DateCreated" > "Extent1"."TimeStarted" AND
        "Extent2"."DateCreated" < "Extent1"."TimeFinished"
WHERE
    "Extent1"."TimeStarted" IS NOT NULL AND
    "Extent1"."TimeFinished" IS NOT NULL AND
    FALSE = "Extent1"."IsDeleted" AND
    "Extent1"."TimeFinished" < '2016-02-06'
GROUP BY "Extent2"."AppId", "Extent2"."DateCreated"
HAVING COUNT(*) >= 2;

我猜这是返回重复项(因此一对值被计算两次)。但是,一行在update 语句中只更新一次(因此同一对只更新一次)。

【讨论】:

  • 不。此组合不能为 Null 复合主键。
  • @AnestisKivranoglou Rows from "dbo"."Positions" 可以被 "dbo"."Route" 表克隆。
  • 是的。 10k Rows 是 Count >2 。你是对的。但我现在有点失去它了。 Select 是否因为它们属于多个路由而两次获取某些行?
  • 是的,Route 表中有 {appId,DateCreated} 对具有多个(重叠){TimeStarted,TimeFinished} 间隔。
  • 是 Cross 通过调用 Distinct 确认了这一点。非常感谢!!!您在搜索一个不存在的问题时为我省去了很多麻烦!
【解决方案2】:

您没有使用子查询中的任何值来进行更新,您只是在检查跨越“dateCreated”的记录是否存在存在并且(也许)使用常量/文字值更新它。

UPDATE "dbo"."Positions" dst
SET "ArchiveUntil" = '2020-02-16'
WHERE EXISTS (
    SELECT 1
    FROM "dbo"."Route" src
    WHERE dst."BoundAppId" = src."AppId" 
      AND dst."DateCreated" > src."TimeStarted"
      AND dst."DateCreated" < src."TimeFinished"

      -- the two conditions below are redundant
      -- AND src."TimeStarted" IS NOT NULL
      -- AND src."TimeFinished" IS NOT NULL
      AND src."IsDeleted" <> True
      AND src."TimeFinished" < '2016-02-06'
        ) ;

【讨论】:

  • 您是说,由于我不使用 Routes 表中的任何值,所以我不应该使用 Inner Join?刚刚用我最初的查询对您的查询进行了基准测试,您的建议运行速度似乎快了 30%。
  • 不,我是说你不需要它。您只需要验证是否存在重叠间隔。 (或:一个或多个重叠区间)
猜你喜欢
  • 1970-01-01
  • 2012-11-21
  • 1970-01-01
  • 1970-01-01
  • 2022-08-17
  • 1970-01-01
  • 2021-01-26
  • 2018-03-14
  • 1970-01-01
相关资源
最近更新 更多