我想知道以下脚本是否可以某种方式进行优化。它确实在磁盘上写了很多东西,因为它可能删除了最新的行并重新插入它们。我正在考虑应用“在重复键更新中插入…”之类的东西,并发现了单行更新的一些可能性,但我不知道如何在的上下文中应用它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;
编辑:
的架构web_member
,watson_searchentry
,web_user
,web_country
:http://pastebin.com/3tRVPPVi。
要点是更新列title
和content
中的内容watson_searchentry
。表上有一个触发器,可search_tsv
根据这些列设置列的值。
(content_type_id, object_id_int)
inwatson_searchentry
是表中的唯一对,但是atm索引不存在(没有用)。
该脚本最多应每天运行一次,以完全重建搜索索引,并且偶尔在导入一些数据之后运行。
如果您确实需要这些列,NOT NULL
并且确实需要将字符串'default'
作为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';
等等。
然后,您不必每次都手动插入这些值。
另外:object_id text NOT NULL, object_id_int INTEGER
?真奇怪 我想你有你的理由…
我将遵循您的更新要求:
主要的一点是要更新的列
title
和content
在watson_searchentry
当然,您 必须 添加 UNIQUE 约束来满足您的要求:
ALTER TABLE watson_searchentry
ADD CONSTRAINT ws_uni UNIQUE (content_type_id, object_id_int)
将使用随附的索引。通过此查询开始。
顺便说一句,我几乎从未varchar(n)
在Postgres中使用过。只是text
。
with.html#QUERIES-WITH-MODIFYING)查询
可以将其重写为具有数据修改通用表表达式(也称为“可写” 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
这些行将改为更新。
因此,我避免在final中插入之前未删除的行INSERT
。
可以轻松地包装到SQL或PL / pgSQL函数中以供重复使用。
不适合大量并发使用。比您拥有的功能要好得多,但仍不能100%健壮地抵抗并发写入。但是,根据您更新的信息,这不是问题。
用DELETE和INSERT替换UPDATE可能会或可能不会昂贵得多。在内部,由于MVCC模型,每个UPDATE都会产生新的行版本。
如果您不太在意保留旧行,则较简单的方法可能会更快:删除所有内容并插入新行。同样,包装到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
值并简化代码,但比简单的串联慢一些。
还:
表上有一个触发器,可
search_tsv
根据这些列设置列的值。
将逻辑合并到该功能中会更快-如果这是唯一需要触发器的时间。否则,可能不值得大惊小怪。
问题内容: 我在一个表中有触发器,并且想在插入,更新或删除行时读取值。怎么做?下面的代码不起作用,出现错误 问题答案: 请注意,其含义与相同,并给出每一行的每种组合。我怀疑这就是你想要的。 这样的事情可能会帮助您入门… 然后根据您要执行的操作,使用或引用您感兴趣的表,等等。 最后,请注意和是 表, 并且可以(并且确实)包含多个记录。 如果您一次插入10条记录,该表将包含所有10条记录。删除和表也
问题内容: 我想以一种可为我的系统恢复的方式重命名PostgreSQL(9.6)表(使用JPA / Hibernate的Java应用程序) 在我的Java代码中,JPA实体将具有以下注释 ,数据库将具有名为的等效表。 我想将表重命名为,以便可以逐步更新数据库和Java应用程序,从而允许失败和回滚。 典型的步骤是 创建in的副本 确保两种读/写都可用(即,两种方式都复制了数据) 更新Java应用程序
问题内容: 在执行包含多行的语句时,我想跳过重复的条目,否则它们会导致失败。经过研究后,我的选择似乎是使用以下任一方法: 这意味着要付出一定代价进行不必要的更新,或者 这暗示了其他类型的失败的邀请。 这些假设对吗?跳过可能导致重复的行并继续其他行的最佳方法是什么? 问题答案: 我建议使用。 如果使用,那么如果该行导致重复键,则实际上不会插入该行。但是该语句不会产生错误。而是生成警告。这些情况包括:
问题内容: 现在已经在网上浏览了一段时间,似乎看不到任何与我想要的东西类似的东西。我知道这与我编写查询的方式有关,但是任何帮助将不胜感激。 我正在尝试做的基础知识是: 如果表中不存在,则将其插入表中 更新项目(如果存在) 它以以下格式存在: 名称,条形码,物品,数量,位置,价格和日期 名称-可以在多行条形码中使用-用于特定项目,但可以用作多个位置项目-与条形码相同,但包含名称数量-自我说明的位置-
问题内容: 这个问题已经在这里有了答案 : 如果存在使用VB.net更新其他插入(SQL参数化查询) (3个答案) 7年前关闭。 我有以下查询: 我需要查看表中是否有任何记录,是否有更新而不是其他插入。如何实现? 问题答案: 您可以在SQL中使用Exists函数。例如 这应该够了吧
delete 操作符用于删除对象的某个属性;如果没有指向这个属性的引用,那它最终会被释放。(MDN) delete 操作符可以删除对象的一个属性。 JavaScript 中的关键字与其他语言略有不同,如 C++ 中的 delete 关键字会释放内存,JavaScript中不会,只有当一个值的引用归零时,才会被释放。 1. 使用 delete delete 操作符在与操作数运算结束后,会返回一个布尔