Жила-была большая-пребольшая база, и была в ней таблица на 300 миллионами записей. Хранились в таблице складские данные, и был в ней столбец deleted, в котором помечалось, если товар со склада перемещался в магазин. И графана с забиксом были красные-красные, потому что приходил в базу запрос “а дай-ка мне товары, которые не перемещены в магазин”, в котором было условие WHERE deleted IS NOT true.

Попробуем провести эксперимент.

Создадим таблицу из двух колонок и признака, удалена запись или нет

CREATE TABLE IF NOT EXISTS public.some_table
(
    column1 text COLLATE pg_catalog."default" NOT NULL,
    column2 integer NOT NULL DEFAULT 0,
    deleted boolean NOT NULL
);

CREATE INDEX IF NOT EXISTS deleted_index
    ON public.some_table USING btree
    (deleted ASC NULLS LAST);

Сгенерируем 10 тысяч значений

INSERT INTO some_table (deleted, column1, column2) 
SELECT true, 'x', s.column2 
FROM generate_series(1, 10000) AS s (column2);

Случайным образом выставим признак deleted

UPDATE some_table
SET deleted = random() > 0.5;

А одинаковый ли результат будет, проверим ?

# SELECT COUNT(*) FROM some_table
# WHERE deleted is not true
# UNION ALL
# SELECT COUNT(*) FROM some_table
# WHERE deleted is false;
 count
-------
  4995
  4995
(2 rows)

А что с планами запросов ?

# EXPLAIN ANALYZE SELECT COUNT(*) FROM some_table
# WHERE deleted is not true;
                                                    QUERY PLAN
------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=221.49..221.50 rows=1 width=8) (actual time=0.967..0.968 rows=1 loops=1)
   ->  Seq Scan on some_table  (cost=0.00..209.00 rows=4995 width=0) (actual time=0.072..0.811 rows=4995 loops=1)
         Filter: (deleted IS NOT TRUE)
         Rows Removed by Filter: 5005
 Planning Time: 0.105 ms
 Execution Time: 0.995 ms
(6 rows)

# EXPLAIN ANALYZE SELECT COUNT(*) FROM some_table
# WHERE deleted is false;
                                                    QUERY PLAN

-------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=136.19..136.19 rows=1 width=8) (actual time=0.603..0.603 rows=1 loops=1)
   ->  Index Only Scan using deleted_index on some_table  (cost=0.29..123.70 rows=4995 width=0) (actual time=0.025..0.391 rows=4995 loops=1)
         Index Cond: (deleted = false)
         Heap Fetches: 0
 Planning Time: 0.091 ms
 Execution Time: 0.625 ms
(6 rows)

#

Вывод

`WHERE <что-то> IS NOT true" - плохо
"WHERE <что-то> IS false" - хорошо
(но надо не забыть создать индекс)

Как можно найти такие запросы

Например, при помощи pg_stat_statements:

SELECT calls, round(total_time/calls) "average", round(total_exec_time), query 
FROM pg_stat_statements 
WHERE lower(query) like '%is not true%'
ORDER BY total_exec_time desc