网页对表有多个排序选项是很常见的。现在我有一个案例,有12个选项(ordenable列)。最简单的(我所知道的)方法是构建连接字符串的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
;
有关多个订购选择的最佳做法是什么?在我的替代代码中使用索引利用会发生什么?
答案 0 :(得分:1)
首先,@order
是无效的PostgreSQL语法。您可能从MS SQL Server或MySQL借用了语法样式。你不能在像这样的普通SQL查询中使用变量。
在PostgreSQL中你可能会create a function。您可以在那里使用变量,只需删除@
。
按 ARRAY 排序通常相当慢 - 在您的情况下不是必需的。您可以简化为:
ORDER BY
CASE _order
WHEN 1 THEN c2
WHEN 2 THEN c3 * -1
ELSE NULL -- undefined!
END
, c1
但是,像这样的CASE表达式不能使用普通索引。所以,如果你正在寻找性能,一种方式(几种)就像这样plpgsql function:
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选项,你也可以写两个 功能
创建multi-column indexes on (c2, c1)
和(c3 DESC, c1)
以获得最佳效果。但请注意,维护索引也会带来成本,特别是如果您的表看到很多写操作。
正如我所说,CASE结构不会使用普通索引。 Indexes on expressions将是一个选项,但您的示例中的内容超出了范围。
所以,如果你想要性能,在你的应用程序中构建查询(第一种方法)或编写一个服务器端函数(可能使用动态SQL和EXECUTE),它在PostgreSQL中做了类似的事情。带有复杂WHERE
语句的CASE
子句有效,但速度较慢。