Postgresql _bid.bid>=新的.bid然后 引发异常“新出价必须高于上一次:%>=%”,上一次出价,新出价; 如果结束; 更新拍卖出价集,将出价集替换为=NEW.id,其中id=先前的出价.id; 如果结束; 如果结束; 归还新的; 结束; $function$; 创建触发器尝试拍卖出价 插入前 在拍卖中(出价)(活跃) 每行 执行程序func_拍卖_出价检查() ;

Postgresql _bid.bid>=新的.bid然后 引发异常“新出价必须高于上一次:%>=%”,上一次出价,新出价; 如果结束; 更新拍卖出价集,将出价集替换为=NEW.id,其中id=先前的出价.id; 如果结束; 如果结束; 归还新的; 结束; $function$; 创建触发器尝试拍卖出价 插入前 在拍卖中(出价)(活跃) 每行 执行程序func_拍卖_出价检查() ;,postgresql,Postgresql,由于这是我觉得有趣的事情,我创建了一个示例结构,它可能远远不够完美,但可能是一个起点 警告:由于新的 TL;博士 带有测试和数据结果的在线示例: 长版本 结构说明: 1.拍卖桌 创建表拍卖( id串行主键, 标题文本不为空, 投标最小数值(18,2)不为空默认值为0.00, 开始时间时间时间戳不为空, 结束时间timestamptz不为空 ); 使用gist(id、tstzrange(开始时间、结束时间))创建在拍卖时打开的索引idx_拍卖; 在这里,我基本上只是从一个最小值开始,但至少考虑了

由于这是我觉得有趣的事情,我创建了一个示例结构,它可能远远不够完美,但可能是一个起点

警告:由于新的

TL;博士 带有测试和数据结果的在线示例:

长版本 结构说明:

1.拍卖桌
创建表拍卖(
id串行主键,
标题文本不为空,
投标最小数值(18,2)不为空默认值为0.00,
开始时间时间时间戳不为空,
结束时间timestamptz不为空
);
使用gist(id、tstzrange(开始时间、结束时间))创建在拍卖时打开的索引idx_拍卖;
在这里,我基本上只是从一个最小值开始,但至少考虑了主动拍卖和封闭拍卖。这就是为什么有一个
GIST
索引:

索引idx_拍卖_公开 这将确保快速返回用于获取所有当前活动(或在任何时间点打开)的查询,例如:

从拍卖中选择*其中tstzrange(开始时间、结束时间)@>当前时间戳;
计划(数千次拍卖):

此外,它也有助于触发功能,该功能需要通过以下查询检查所引用的拍卖是否存在并且实际上仍处于打开状态:

从拍卖中选择最低出价,其中id=NEW.auction\u id和tstzrange(开始时间、结束时间)@>NEW.bid\u时间;
执行计划示例:

                                                        QUERY PLAN                                                        
--------------------------------------------------------------------------------------------------------------------------
 Index Scan using idx_auction_open on auction  (cost=0.15..2.37 rows=1 width=8) (actual time=0.042..0.043 rows=1 loops=1)
   Index Cond: ((id = 1) AND (tstzrange(start_time, end_time) @> CURRENT_TIMESTAMP))
   Buffers: shared hit=3
 Planning Time: 0.156 ms
 Execution Time: 0.072 ms
(5 rows)
                                                                                          QUERY PLAN                                                                                           
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.15..2.38 rows=1 width=44) (actual time=0.022..0.025 rows=1 loops=1)
   Buffers: shared hit=2
   ->  Merge Append  (cost=0.15..2.38 rows=1 width=44) (actual time=0.020..0.020 rows=1 loops=1)
         Sort Key: auction_bids_active.bid_time DESC
         Buffers: shared hit=2
         ->  Index Scan Backward using auction_bids_active_auction_id_user_id_bid_time_idx on auction_bids_active  (cost=0.14..2.36 rows=1 width=44) (actual time=0.018..0.019 rows=1 loops=1)
               Index Cond: ((auction_id = 1) AND (user_id = 123))
               Buffers: shared hit=2
 Planning Time: 0.468 ms
 Execution Time: 0.079 ms
(10 rows)
2.拍卖价格表
创建表拍卖\u出价(
序列号不为空,
用户id整数不为空,
拍卖id整数非空引用拍卖(id),
投标数字(18,2)不为空,
bid_时间戳不为空,
将_替换为整数
)按列表划分(替换为);
为中的值创建表auction\u bids\u auction\u bids的活动分区(NULL);
创建表auction\u bids\u auction\u bids DEFAULT的历史分区;
在拍卖出价(id)上创建索引idx\U拍卖出价\U id;
创建索引idx_auction_bids_在auction_bids上活动(auction_id、user_id、bid_time),其中(替换为NULL);
创建索引idx_auction_bids_Historical ON auction_bids(拍卖id、用户id、出价时间描述),其中(替换为不为空);
在这里,我实际上为默认分区使用了新的PostgreSQL 11功能,其中默认分区
auction\u bids\u history
保存所有历史拍卖出价,而另一个分区
auction\u bids\u active
配置为仅包含最新出价

这创建了一个很好的设置,为PostgreSQL提供了一个分区修剪(实际扫描哪些分区)的提示,正如我们预期的那样,历史分区的增长速度要比活动分区快得多

例如,以下是所有活动拍卖及其活动出价的查询执行计划:

解释(分析、缓冲区)
选择a.标题、b.用户id、b.投标、b.投标时间
从拍卖竞价作为b内部加入拍卖作为a ON(a.id=b.auction\u id)
其中,替换为为空且tstzrange(a.start\u time,a.end\u time)@>当前\u时间戳
按拍卖id、出价描述、用户id排序的订单;
(目前顺序扫描在这里完全正常)

我还添加了一些帮助器索引,这些索引对于较高的出价可能非常有用,特别是对于通过触发器函数搜索以前的活动条目,例如:

选择*进入上一次投标
从拍卖到拍卖
哪里
替换为“”的值为空
及
拍卖\u id=NEW.auction\u id
及
user\u id=NEW.user\u id
按投标时间说明订购
限值1;
执行计划示例:

                                                        QUERY PLAN                                                        
--------------------------------------------------------------------------------------------------------------------------
 Index Scan using idx_auction_open on auction  (cost=0.15..2.37 rows=1 width=8) (actual time=0.042..0.043 rows=1 loops=1)
   Index Cond: ((id = 1) AND (tstzrange(start_time, end_time) @> CURRENT_TIMESTAMP))
   Buffers: shared hit=3
 Planning Time: 0.156 ms
 Execution Time: 0.072 ms
(5 rows)
                                                                                          QUERY PLAN                                                                                           
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.15..2.38 rows=1 width=44) (actual time=0.022..0.025 rows=1 loops=1)
   Buffers: shared hit=2
   ->  Merge Append  (cost=0.15..2.38 rows=1 width=44) (actual time=0.020..0.020 rows=1 loops=1)
         Sort Key: auction_bids_active.bid_time DESC
         Buffers: shared hit=2
         ->  Index Scan Backward using auction_bids_active_auction_id_user_id_bid_time_idx on auction_bids_active  (cost=0.14..2.36 rows=1 width=44) (actual time=0.018..0.019 rows=1 loops=1)
               Index Cond: ((auction_id = 1) AND (user_id = 123))
               Buffers: shared hit=2
 Planning Time: 0.468 ms
 Execution Time: 0.079 ms
(10 rows)
3.规则执行的触发器 现在,为了真正从上述功能中获益,我创建了一个触发器函数,它基本上有3个功能:

  • 验证引用的拍卖是否存在,是否当前处于活动状态,以及新出价是否至少具有拍卖最低值
  • 验证新标书是否高于现有标书(如果存在)
  • 通过设置
    replacemented\u by
    字段将现有条目(如果存在)移动到历史分区(这在PostgreSQL 11中也是新的)
  • 在该触发器完成后,新记录实际上被插入到
    auction\u bids\u active
    分区中(因为
    NULL
    值被
    替换)

    创建或替换函数func\u auction\u bid\u check()
    返回触发器
    语言plpgsql
    作为$function$
    声明
    最小数值(18,2);
    上一次出价拍卖出价%行类型;
    开始
    NEW.bid\u time:=当前\u时间戳;
    将NEW.u替换为:=NULL;
    从拍卖中选择最低出价,其中id=NEW.auction\u id和tstzrange(开始时间、结束时间)@>NEW.bid\u时间;
    如果(未找到),则
    引发异常“ID%@%无(公开)拍卖可用”,NEW.auction\u ID,NEW.bid\u time;
    ELSIF(最小值>新出价)然后
    提出例外情况“新出价必须高于拍卖最低%:%”,最低,新出价;
    其他的
    选择*进入上一次投标
    从拍卖到拍卖
    哪里
    替换为“”的值为空
    及
    拍卖\u id=NEW.auction\u id
    及
    user\u id=NEW.user\u id
    按投标时间说明订购
    限值1;
    如果找到了
    如果以前的投标>=新的投标,则
    引发异常“新出价必须高于上一次:%>=%”,上一次出价,新出价;
    如果结束;
    更新