优化INSERT/UPDATE/DELETE操作

2023-11-29

我想知道是否可以以某种方式优化以下脚本。它确实向磁盘写入了大量数据,因为它删除了可能是最新的行并重新插入它们。我正在考虑应用诸如“在重复键更新时插入...”之类的内容,并发现了单行更新的一些可能性,但我不知道如何在以下上下文中应用它INSERT INTO ... SELECT query.

CREATE OR REPLACE FUNCTION update_member_search_index() RETURNS VOID AS $$
DECLARE
   member_content_type_id INTEGER;
BEGIN
   member_content_type_id :=
      (SELECT id FROM django_content_type
       WHERE app_label='web' AND model='member');

   DELETE FROM watson_searchentry WHERE content_type_id = member_content_type_id;

   INSERT INTO watson_searchentry (engine_slug, content_type_id, object_id
                                 , object_id_int, title, description, content
                                 , url, meta_encoded)
   SELECT 'default',
         member_content_type_id,
         web_member.id,
         web_member.id,
         web_member.name,
         '',
         web_user.email||' '||web_member.normalized_name||' '||web_country.name,
         '',
         '{}'
   FROM web_member
   INNER JOIN web_user ON (web_member.user_id = web_user.id)
   INNER JOIN web_country ON (web_member.country_id = web_country.id)
   WHERE web_user.is_active=TRUE;
END;
$$ LANGUAGE plpgsql;

EDIT:的模式web_member, watson_searchentry, web_user, web_country: http://pastebin.com/3tRVPPVi.

重点是更新列title and content in watson_searchentry。表上有一个触发器设置列的值search_tsv基于这些列。

(content_type_id, object_id_int) in watson_searchentry是表中唯一的对,但 atm 索引不存在(它没有用)。

该脚本每天最多应运行一次,以完全重建搜索索引,偶尔在导入一些数据后运行。


修改表定义

如果您确实需要这些列NOT NULL你确实需要字符串'default'默认为engine_slug,我建议引入列默认值:

COLUMN           |          TYPE           |      Modifiers
-----------------+-------------------------+---------------------
 id              | INTEGER                 | NOT NULL DEFAULT ... 
 engine_slug     | CHARACTER VARYING(200)  | NOT NULL DEFAULT 'default'
 content_type_id | INTEGER                 | NOT NULL
 object_id       | text                    | NOT NULL
 object_id_int   | INTEGER                 |
 title           | CHARACTER VARYING(1000) | NOT NULL
 description     | text                    | NOT NULL DEFAULT ''
 content         | text                    | NOT NULL
 url             | CHARACTER VARYING(1000) | NOT NULL DEFAULT ''
 meta_encoded    | text                    | NOT NULL DEFAULT '{}'
 search_tsv      | tsvector                | NOT NULL
 ...

DDL 语句将是:

ALTER TABLE watson_searchentry ALTER COLUMN  engine_slug DEFAULT 'default';

Etc.

这样您就不必每次都手动插入这些值。

Also: object_id text NOT NULL, object_id_int INTEGER?这很奇怪。我想你也有你的理由...

我将满足您更新的要求:

重点是更新列title and content in watson_searchentry

当然,你must add a UNIQUE强制执行您的要求的约束:

ALTER TABLE watson_searchentry
ADD CONSTRAINT ws_uni UNIQUE (content_type_id, object_id_int)

将使用随附的索引。对于初学者来说,通过这个查询。

顺便说一句,我几乎从不使用varchar(n)在 Postgres 中。只是text. 原因之一。

查询方式数据修改 CTE

这可以用数据修改公用表表达式(也称为“可写”CTE)重写为单个 SQL 查询。需要 Postgres 9.1 或更高版本。
此外,该查询仅删除必须删除的内容,并更新可以更新的内容。

WITH  ctyp AS (
   SELECT id AS content_type_id
   FROM   django_content_type
   WHERE  app_label = 'web'
   AND    model = 'member'
   )
, sel AS (
   SELECT ctyp.content_type_id
         ,m.id       AS object_id_int
         ,m.id::text AS object_id       -- explicit cast!
         ,m.name     AS title
         ,concat_ws(' ', u.email,m.normalized_name,c.name) AS content
         -- other columns have column default now.
   FROM   web_user    u
   JOIN   web_member  m  ON m.user_id = u.id
   JOIN   web_country c  ON c.id = m.country_id
   CROSS  JOIN ctyp
   WHERE  u.is_active
   )
, del AS (     -- only if you want to del all other entries of same type
   DELETE FROM watson_searchentry w
   USING  ctyp
   WHERE  w.content_type_id = ctyp.content_type_id
   AND    NOT EXISTS (
      SELECT 1
      FROM   sel
      WHERE  sel.object_id_int = w.object_id_int
      )
   )
, up AS (      -- update existing rows
   UPDATE watson_searchentry 
   SET    object_id = s.object_id
         ,title     = s.title
         ,content   = s.content
   FROM   sel s
   WHERE  w.content_type_id = s.content_type_id
   AND    w.object_id_int   = s.object_id_int
   )
               -- insert new rows
INSERT  INTO watson_searchentry (
        content_type_id, object_id_int, object_id, title, content)
SELECT  sel.*  -- safe to use, because col list is defined accordingly above
FROM    sel
LEFT    JOIN watson_searchentry w1 USING (content_type_id, object_id_int)
WHERE   w1.content_type_id IS NULL;
  • 子查询在django_content_type总是返回单个值?否则,CROSS JOIN可能会引起麻烦。

  • 第一个 CTEsel收集要插入的行。注意我是如何选择的匹配列名简化事情。

  • 在 CTE 中del我避免删除可以更新的行。

  • 在 CTE 中up这些行会被更新。

  • 因此,我避免在最后插入之前未删除的行INSERT.

可以轻松包装到 SQL 或 PL/pgSQL 函数中以供重复使用。

对于大量并发使用不安全。比您拥有的功能好得多,但对于并发写入仍然不是 100% 稳健。但根据您更新的信息,这不是问题。

用 DELETE 和 INSERT 替换 UPDATE 的成本可能会高很多,也可能不会高很多。在内部,每次更新都会产生一个新的行版本,因为MVCC模型.

速度第一

如果您并不真正关心保留旧行,则更简单的方法可能会更快:删除所有内容并插入新行。此外,包装到 plpgsql 函数中可以节省一些规划开销。您的函数基本上是通过一些小的简化并观察上面添加的默认值:

CREATE OR REPLACE FUNCTION update_member_search_index()
  RETURNS VOID AS
$func$
DECLARE
   _ctype_id int := (
      SELECT id
      FROM   django_content_type
      WHERE  app_label='web'
      AND    model = 'member'
      );  -- you can assign at declaration time. saves another statement
BEGIN
   DELETE FROM watson_searchentry
   WHERE content_type_id = _ctype_id;

   INSERT INTO watson_searchentry
         (content_type_id, object_id, object_id_int, title, content)
   SELECT _ctype_id, m.id, m.id::int,m.name
         ,u.email || ' ' || m.normalized_name || ' ' || c.name
   FROM   web_member  m
   JOIN   web_user    u USING (user_id)
   JOIN   web_country c ON c.id = m.country_id
   WHERE  u.is_active;
END
$func$ LANGUAGE plpgsql;

我什至不使用concat_ws(): 是安全的NULL值并简化了代码,但比简单串联慢一点。

Also:

表上有一个触发器设置列的值search_tsv基于这些列。

如果这是唯一需要触发器的时间,则将逻辑合并到该函数中会更快。否则,可能不值得大惊小怪。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

优化INSERT/UPDATE/DELETE操作 的相关文章

随机推荐

  • Selenium-IDE:如何验证/断言页面刷新

    我的页面上有一个链接 单击该链接会刷新此页面 如何使用 Selenium IDE 验证页面是否确实已刷新 重新加载 我通过断言页面上最初存在的元素在刷新后不存在于页面上来解决这个问题 然后等到页面完全刷新 并断言该元素再次存在 刷新并等待
  • React router dom 中的链接不会加载页面,仅 url 浏览器导航会更改

    React router dom v5 和 React 16 我的加载应用程序组件包含 ReactDOM render
  • 如何通过 Android 应用程序编辑日历事件

    我如何通过 Android 应用程序编辑日历中的日历事件 任何人都知道如何在日历应用程序中打开议程活动 从日历中读取数据后 试试这个 将单次事件添加到日历 要将条目添加到特定日历 我们需要使用 ContentValues 配置要插入的日历条
  • unicodecsv 读取器从 unicode 字符串无法正常工作?

    我在将 unicode CSV 字符串读入 python unicodescv 时遇到问题 gt gt gt import unicodecsv StringIO gt gt gt f StringIO StringIO u gt gt g
  • 在sqlite3数据库中插入1000000行

    我想向数据库中插入 10 00 000 行 但是插入的时间太长了 例如现在我正在尝试 2055 行 需要 3 分钟才能将这些数据上传到数据库中 对于 2055 个条目来说 这个时间太多了 以下是我将数据插入数据库的方法 public voi
  • numpy var() 和 pandas var() 之间的区别

    最近遇到的一件事让我注意到numpy var and pandas DataFrame var or pandas Series var 给出不同的值 我想知道它们之间有什么区别吗 这是我的数据集 Country GDP Area Cont
  • 使用 Kafka Streams DSL 进行两步窗口聚合

    假设我有一个流 stream 1 每秒由 1 个数据点组成 我想计算一个派生流 stream 5 其中包含使用 5 秒的跳跃窗口和另一个流 stream 10 的总和它基于包含使用 10 秒跳跃窗口的总和的 stream 5 需要分别对每个
  • 在 Rails 4 中,Model.scoped 已被弃用,但 Model.all 无法替代它

    启动 轨道 4 Model scoped现已弃用 DEPRECATION WARNING Model scoped is deprecated Please use Model all instead 但是 有一个区别Model scope
  • 在表中添加和删除数据 - React

    我正在 React 中按表格制作一个简单的姓名和电子邮件列表 我想从服务器获取数据 然后动态添加或删除人员 这是我使用 React 的第一步 所以我遇到了一个问题 import React Component from react impo
  • Angular 2 - 获取日期

    我在模板中显示日期 p Datum p b data wageStatement date 这是它的渲染方式 2017 03 08T13 00 03 114Z 但我只想以这种格式显示日期 2017 03 08 Use DatePipe p
  • Java 泛型:通配符 与类型参数?

    我正在刷新有关 Java 泛型的知识 因此 我转向 Oracle 提供的优秀教程 并开始为我的同事准备一个演示文稿 我在中看到了有关通配符的部分tutorial说的是 考虑以下方法 printList public static void
  • MySQL错误150,无法创建表

    我在创建表格时遇到问题 我不明白出了什么问题 phpMyAdmin 在主键声明旁边设置错误指示器 我不明白为什么这是错误的 该表是一个子表 它与另一个表具有一对多的标识关系 CREATE TABLE IF NOT EXISTS ruilen
  • 您能解释一下 STA 和 MTA 吗?

    您能用自己的话解释一下STA和MTA吗 另外 什么是公寓线程 它们仅与 COM 相关吗 如果是这样 为什么 COM 线程模型称为 单元 模型 其中初始化的 COM 对象的执行上下文与单个线程 单线程单元 或多个线程 多线程单元 相关联 在此
  • 如何在 Fortran 中计算大整数?

    我需要生成一些大整数 请参见下面的示例 Input Result 40 165580141 80 37889062373143906 120 8670007398507948658051921 160 1983924214061919432
  • Spark 作业执行时间随着非常宽的数据集和列数呈指数增长[重复]

    这个问题已经存在了 我在 Spark 中创建了一个固定宽度的文件导入解析器 并对各种数据集执行了一些执行测试 它在最多 1000 列的情况下工作正常 但是 随着列数和固定宽度长度的增加 Spark 作业性能迅速下降 在20k列和固定宽度长度
  • 使用 JavaScript 访问变量对象的属性

    我有一个 js 对象 如下所示 var object divisions ocd division country us name United States 我想访问嵌套对象下列出的属性 ocd division country us 又
  • SSRS 中 PDF/打印报告的目录

    这是我所知道的 我知道文档图和书签可以在屏幕上使用 但不能在 pdf 中使用 SSRS 不具备将带页码的打印目录生成 pdf 的开箱即用功能 我知道可以通过将文档结构图导出到Word来生成TOC 这种方法不适用于我的情况 全局变量可以存储页
  • Margin 的左边距:自动元素 = 填充 100% 宽度溢出项目的左侧

    让我用下面的 HTML 来演示这个问题 section style text align center section
  • AngularJS 中 $broadcast()、$emit() 和 $on() 的用法

    我明白那个 Broadcast Emit And On 用于在一个控制器中引发事件并在另一个控制器中进行处理 如果可能的话 有人可以给我一些关于上述三个用法的实时示例吗 因为我是新手angular JS 我已浏览以下链接并了解基本用法 ht
  • 优化INSERT/UPDATE/DELETE操作

    我想知道是否可以以某种方式优化以下脚本 它确实向磁盘写入了大量数据 因为它删除了可能是最新的行并重新插入它们 我正在考虑应用诸如 在重复键更新时插入 之类的内容 并发现了单行更新的一些可能性 但我不知道如何在以下上下文中应用它INSERT