GVKun编程网logo

Postgres中的Go和IN子句

18

对于想了解Postgres中的Go和IN子句的读者,本文将是一篇不可错过的文章,并且为您提供关于php–为PostgreSQL中的WHEREIN子句绑定多个行和列、postgresql–JOIN子句中

对于想了解Postgres中的Go和IN子句的读者,本文将是一篇不可错过的文章,并且为您提供关于php – 为PostgreSQL中的WHERE IN子句绑定多个行和列、postgresql – JOIN子句中的USING构造在某些情况下会引入优化障碍吗?、postgresql – pg_restore:[archiver]输入文件在postgres中的错误太短、postgresql – Postgres where子句比较时间戳的有价值信息。

本文目录一览:

Postgres中的Go和IN子句

Postgres中的Go和IN子句

我正在尝试使用pq驱动程序对Go中的PostgreSQL数据库执行以下查询:

SELECT COUNT(id)FROM tagsWHERE id IN (1, 2, 3)

哪里1, 2, 3过去了tags := []string{"1", "2", "3"}

我尝试了很多不同的事情,例如:

s := "(" + strings.Join(tags, ",") + ")"if err := Db.QueryRow(`    SELECT COUNT(id)    FROM tags    WHERE id IN $1`, s,).Scan(&num); err != nil {    log.Println(err)}

结果是pq: syntax error at or near "$1"。我也试过

if err := Db.QueryRow(`    SELECT COUNT(id)    FROM tags    WHERE id IN ($1)`, strings.Join(stringTagIds, ","),).Scan(&num); err != nil {    log.Println(err)}

这也失败了 pq: invalid input syntax for integer: "1,2,3"

我也尝试直接传递一片整数/字符串并得到sql: converting Exec argument #0''s type: unsupported type[]string, a slice

那么如何在Go中执行此查询?

答案1

小编典典

预先构建SQL查询(防止SQL注入)

如果要为每个值生成一个带有参数占位符的SQL字符串,则立即生成最终SQL会更容易。

请注意,由于值是strings,因此存在进行SQL注入攻击的位置,因此我们首先测试所有string值是否确实是数字,并且仅在以下情况下进行:

tags := []string{"1", "2", "3"}buf := bytes.NewBufferString("SELECT COUNT(id) FROM tags WHERE id IN(")for i, v := range tags {    if i > 0 {        buf.WriteString(",")    }    if _, err := strconv.Atoi(v); err != nil {        panic("Not number!")    }    buf.WriteString(v)}buf.WriteString(")")

执行它:

num := 0if err := Db.QueryRow(buf.String()).Scan(&num); err != nil {    log.Println(err)}

使用 ANY

您还可以使用Postgresql的ANY,其语法如下:

expression operator ANY (array expression)

使用该查询,我们的查询可能如下所示:

SELECT COUNT(id) FROM tags WHERE id = ANY(''{1,2,3}''::int[])

在这种情况下,您可以将数组的文本形式声明为参数:

SELECT COUNT(id) FROM tags WHERE id = ANY($1::int[])

可以这样简单地构建:

tags := []string{"1", "2", "3"}param := "{" + strings.Join(tags, ",") + "}"

请注意,在这种情况下不需要检查,因为数组表达式将不允许SQL注入(而是将导致查询执行错误)。

所以完整的代码:

tags := []string{"1", "2", "3"}q := "SELECT COUNT(id) FROM tags WHERE id = ANY($1::int[])"param := "{" + strings.Join(tags, ",") + "}"num := 0if err := Db.QueryRow(q, param).Scan(&num); err != nil {    log.Println(err)}

php – 为PostgreSQL中的WHERE IN子句绑定多个行和列

php – 为PostgreSQL中的WHERE IN子句绑定多个行和列

所以我想准备一个类似的查询:

SELECT id FROM users WHERE (branch,cid) IN $1;

然后绑定一个可变长度的行集,如((‘a’,’b’),(‘c’,’d’)).

换句话说,像:

pg_prepare($users,'users_query','SELECT id FROM users WHERE (branch,cid) IN $1');
$result = pg_execute($users,array("(('a','b'),('c','d'))");

我需要拆分这两个的原因是因为我想要准备一次,然后以尽可能少的开销运行它多次.

解决方法

只使用两个记录进行顺序扫描的事实毫无意义.对于如此微小的集合,索引永远不会比seqential扫描快.我构建了一个类似于你的小样本表,并用一百万行填充它,以下查询样式始终如一地生成好的计划和快速执行:

prepare s4 as
select id from users
join (select * from (values ($1,$2),($3,$4)) as v(branch,cid)) as p
using (branch,cid);

explain analyze execute s4('b11','c11','b1234','c1234');
                                                    QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 nested Loop  (cost=0.00..16.65 rows=1 width=4) (actual time=0.199..0.234 rows=2 loops=1)
   ->  Values Scan on "*VALUES*"  (cost=0.00..0.03 rows=2 width=64) (actual time=0.002..0.003 rows=2 loops=1)
   ->  Index Scan using u_i on users  (cost=0.00..8.30 rows=1 width=16) (actual time=0.111..0.112 rows=1 loops=2)
         Index Cond: ((users.branch = "*VALUES*".column1) AND (users.cid = "*VALUES*".column2))
 Total runtime: 0.425 ms

看来你真正的问题是如何将动态确定数量的值对绑定到你的sql.我的PHP非常生疏,阅读在线文档提醒我有多讨厌它,但我认为以下内容会做你想要的,构建上面形式的sql,并根据值的数量动态创建值对占位符的数量你希望绑定.我没有方便的PHP执行环境,所以我甚至没有检查它是否在语法上是正确的,但你应该能够得到这个想法,并在我的例子中解决任何微不足道的错误.

$values = array(
  'a','b','c','d',// etc...
);

$value_placeholders = "";
$sep = "";
for ($i=1; $i <= $count($values); $i+=2) {
  $value_placeholders = $value_placeholders . sprintf("($%u,$%u),",$i,$i+1) . $sep
  $sep = ",";
}

$sql =
  'select id from users ' .
  'join (select * from (values ' . $value_placeholders . ') as v(branch,cid)) as p' .
  'using (branch,cid)';

$result = pg_query_params($dbconn,$sql,$values);

如果你真的只需要一个准备好的声明(并且对于一个无法真正尝试对真实数据集而不是两个记录进行查询的人,我们将完全避免谈论premature optimization),我想我有你的答案:

create index u_i2 on users ((branch||cid));
prepare sa as select id from users where branch||cid in (select unnest($1::text[]));
explain analyze execute sa(ARRAY['b1c1','b1234c1234']);
                                                      QUERY PLAN                                                      
----------------------------------------------------------------------------------------------------------------------
 nested Loop  (cost=12.17..645.78 rows=50000 width=4) (actual time=0.169..0.188 rows=2 loops=1)
   ->  HashAggregate  (cost=0.02..0.03 rows=1 width=32) (actual time=0.018..0.019 rows=2 loops=1)
         ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.010..0.011 rows=2 loops=1)
   ->  Bitmap Heap Scan on users  (cost=12.14..638.25 rows=500 width=16) (actual time=0.082..0.082 rows=1 loops=2)
         Recheck Cond: ((users.branch || users.cid) = (unnest($1)))
         ->  Bitmap Index Scan on u_i2  (cost=0.00..12.02 rows=500 width=0) (actual time=0.078..0.078 rows=1 loops=2)
               Index Cond: ((users.branch || users.cid) = (unnest($1)))
 Total runtime: 0.275 ms

注意::我无法找到获取行对的索引访问权限.但是如果你在两个字段的串联上创建一个功能索引,然后提供这种连接的绑定数组,你会得到一个很好的快速嵌套循环索引扫描.

postgresql – JOIN子句中的USING构造在某些情况下会引入优化障碍吗?

postgresql – JOIN子句中的USING构造在某些情况下会引入优化障碍吗?

我注意到 FROM clause of SELECT queries中的USING结构(而不​​是ON)可能会在某些情况下引入优化障碍.

我的意思是这个关键词:

SELECT *
FROM   a
JOIN   b USING (a_id)

只是在更复杂的情况下.

背景:this comment至this question.

我经常使用它,到目前为止从未注意到任何事情.我会对展示效果或任何进一步信息链接的测试用例非常感兴趣.我的搜索工作空洞了.

完美答案将是一个测试用例,以显示USING(a_id)与替代连接子句ON a.a_id = b.a_id相比具有较差的性能 – 如果这实际上可能发生.

欧文:我同意这样的想法,即使用导致严格排序可能会产生许多边缘情况,在这种情况下可以排除最优计划.我最近在他的查询中帮助过那些有类似内容的人:
LEFT JOIN ( 
     a 
     JOIN b ON a.id = b.a_id
     JOIN c ON b.c_id = c.id
) ON a.id = something.a_id
LEFT JOIN (
     table1 t1
     JOIN table2 t2 ON t1.some_field = t2.other_field
     JOIN talbe3 t3 ON t2.yafield = t3.something_else
) ON ....
repeat a few more times

在他的情况下,这些连接块中最差的是导致嵌套循环连接通过大约200k行,大约20k次(算数),并且因为密钥不能被推送到索引,所以它是顺序扫描.这意味着由于级联计划更改,整个查询大约需要3个小时才能运行.通过分发左连接,可以按下键并在几秒钟内运行查询.当然,这并不完全等同,这就是为什么规划者不能将它们视为等价的原因,因此它将计划作为散列连接,然后进行嵌套循环,这非常缓慢.

每当你严格强制连接按特定顺序进行时,你会引入在执行计划时可能无法获得关键过滤器信息的情况,以及稍后在快速索引扫描/散列连接中可能做的事情可能必须在嵌套循环/顺序扫描中慢得多,因此虽然上面的片段不是立即等效的,但它显示了同样的问题.

postgresql – pg_restore:[archiver]输入文件在postgres中的错误太短

postgresql – pg_restore:[archiver]输入文件在postgres中的错误太短

我试图通过使用命令在我的本地系统中转储数据库:

pg_restore --host=localhost --port=5432 --dbname=dev_db --no-owner --no-privileges db_dump_new.backup

但我收到错误:

pg_restore: [archiver] input file is too short (read 0,expected 5)

我究竟做错了什么?

解决方法

我遇到了同样的错误.在我的情况下,我只是忽略了在命令末尾指定备份文件.

postgresql – Postgres where子句比较时间戳

postgresql – Postgres where子句比较时间戳

我有一个表,其中列是数据类型时间戳

其中包含一天记录的多条记录
我想选择与day相对应的所有行

我该怎么做?

假设你实际上是指时间戳,因为Postgres中没有日期时间

将timestamp列转换为日期,这将删除时间部分:

select *
from the_table
where the_timestamp_column::date = date '2015-07-15';

这将从7月15日返回所有行。

请注意,上面的内容不会使用the_timestamp_column上的索引。如果性能至关重要,则需要在该表达式上创建索引或使用范围条件:

select *
from the_table
where the_timestamp_column >= timestamp '2015-07-15 00:00:00'
  and the_timestamp_column < timestamp '2015-07-16 00:00:00';

关于Postgres中的Go和IN子句的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于php – 为PostgreSQL中的WHERE IN子句绑定多个行和列、postgresql – JOIN子句中的USING构造在某些情况下会引入优化障碍吗?、postgresql – pg_restore:[archiver]输入文件在postgres中的错误太短、postgresql – Postgres where子句比较时间戳等相关内容,可以在本站寻找。

本文标签: