Greater than or equal to ALL() and equal to MAX() speed

后端 未结 4 1459
春和景丽
春和景丽 2021-01-16 03:08

I have a relation in PostgreSQL named product which contains 2 fields: id and quantity, and I want to find the id of the

4条回答
  •  生来不讨喜
    2021-01-16 03:33

    The first query fails if any row has quantity IS NULL (as Gordon demonstrates).
    The second query only fails if all rows have quantity IS NULL. So it should be usable in most cases. (And it's faster.)

    If you need a NULL-safe query in Postgres 12 or older, i.e., NULL is a valid result, then consider:

    SELECT id, quantity
    FROM   product
    WHERE  quantity IS NOT DISTINCT FROM (SELECT MAX(quantity) FROM product);
    

    Or, probably faster:

    SELECT id, quantity
    FROM  (
       SELECT *, rank() OVER (ORDER BY quantity DESC NULLS LAST) AS rnk
       FROM   product
       ) sub
    WHERE  rnk = 1;
    

    See:

    • PostgreSQL equivalent for TOP n WITH TIES: LIMIT "with ties"?

    Postgres 13 adds the standard SQL clause WITH TIES:

    SELECT id
    FROM   product
    ORDER  BY quantity DESC NULLS LAST
    FETCH  FIRST 1 ROWS WITH TIES;
    

    db<>fiddle here

    Works with any amount of NULL values.

    The manual:

    SQL:2008 introduced a different syntax to achieve the same result, which PostgreSQL also supports. It is:

    OFFSET start { ROW | ROWS }
    FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES }
    

    In this syntax, the start or count value is required by the standard to be a literal constant, a parameter, or a variable name; as a PostgreSQL extension, other expressions are allowed, but will generally need to be enclosed in parentheses to avoid ambiguity. If count is omitted in a FETCH clause, it defaults to 1. The WITH TIES option is used to return any additional rows that tie for the last place in the result set according to the ORDER BY clause; ORDER BY is mandatory in this case. ROW and ROWS as well as FIRST and NEXT are noise words that don't influence the effects of these clauses.

    Notably, WITH TIES cannot be used with the (non-standard) short syntax LIMIT n.

    It's the fastest possible solution. Faster than either of your current queries. More important for performance: have an index on (quantity). Or a more specialized covering index to allow index-only scans (a bit faster, yet):

    CREATE INDEX ON product (quantity DESC NULLS LAST) INCLUDE (id);
    

    See:

    • Do covering indexes in PostgreSQL help JOIN columns?

    We need NULLS LAST to keep NULL values last in descending order. See:

    • Sort by column ASC, but NULL values first?

提交回复
热议问题