1

对于一个网页来说,一个表格有多个排序选项是很常见的。现在我有一个案例,其中有 12 个选项(可排序的列)。最简单(据我所知)的方法是构建连接字符串的 SQL 查询。但我想知道这是否是最好的方法。字符串连接是这样的(python 代码):

order = {
    1: "c1 desc, c2",
    2: "c2, c3",
    ...
    12: "c10, c9 desc"
    }
...
query = """
select c1, c2
from the_table
order by %(order)s
"""
...
cursor.execute(query, {'order': AsIs(order[order_option])})
...

order by到目前为止,我的替代解决方案是在子句中放置一系列案例:

select c1, c2
from the_table
order by
    case %(order_option)s
        when 1 then array[c1 * -1, c2]
        when 2 then array[c2, c3]
        else [0.0, 0.0]
    end
    ,
    case %(order_option)s
        when 3 then c4
        else ''
    end
    ,
    ...
    ,
    case when %(order_option)s < 1 or %(order_option)s > 12 then c5 end
;

关于多种订购选择的最佳做法是什么?我的替代代码中的索引利用率会怎样?

4

1 回答 1

1

首先,@order不是有效的 PostgreSQL 语法。您可能从 MS SQL Server 或 MySQL 借用了语法风格。您不能在这样的普通 SQL 查询中使用变量。

在 PostgreSQL 中,您可能会创建一个函数。您可以在那里使用变量,只需删除@.

按ARRAY排序通常相当慢 - 在您的情况下不是必需的。您可以简化为:

ORDER  BY
       CASE _order
          WHEN 1 THEN c2
          WHEN 2 THEN c3 * -1
          ELSE NULL  -- undefined!
       END
     , c1

但是,像这样的 CASE 表达式不能使用普通索引。因此,如果您正在寻找性能,一种(几种)方法是这样的plpgsql 函数

CREATE OR REPLACE FUNCTION foo(int)
  RETURNS TABLE(c1 int, c2 int) AS
$BODY$
BEGIN

CASE $1
WHEN 1 THEN
    RETURN QUERY
    SELECT t.c1, t.c2
    FROM   tbl t
    ORDER  BY t.c2, t.c1;

WHEN 2 THEN
    RETURN QUERY
    SELECT t.c1, t.c2
    FROM   tbl t
    ORDER  BY t.c3 DESC, t.c1;
ELSE
    RAISE WARNING 'Unexpected parameter: "%"', $1;
END CASE;

END;
$BODY$
  LANGUAGE plpgsql STABLE;

这样,即使是普通索引也可以使用。

如果您实际上只有两个 ORDER BY 替代方案,您也可以只编写两个函数。

创建多列索引以 (c2, c1)获得(c3 DESC, c1)最佳性能。但请注意,维护索引也会带来成本,尤其是当您的表看到大量写入操作时。


改写问题的附加答案

正如我所说,CASE 构造不会使用普通索引。表达式上的索引将是一个选项,但您在示例中拥有的内容超出了范围。

因此,如果您想要性能,请在您的应用程序中构建查询(您的第一种方法)或编写在 PostgreSQL 中执行类似操作的服务器端函数(可能使用动态 SQL 和EXECUTE)。WHERE具有复杂语句的子句CASE有效,但速度较慢。

于 2012-01-28T20:59:41.823 回答