powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Between лучше Equal
13 сообщений из 13, страница 1 из 1
Between лучше Equal
    #38982987
Alex Marmuzevich
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Приветствую.

В Postgress 9.2 запросах случайно нарвались на такую хрень:
Для таблиц вида create table a ( id, field1 int, ..., primary key (id)) с indexed (btree) field1 почему-то
field1 between x and x согласно explain plan работает лучше (по стоимости) чем field1 = x.

Это фича такая о которой все знают, или просто локальная аномалия?
...
Рейтинг: 0 / 0
Between лучше Equal
    #38982996
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alex MarmuzevichПриветствую.

В Postgress 9.2 запросах случайно нарвались на такую хрень:
Для таблиц вида create table a ( id, field1 int, ..., primary key (id)) с indexed (btree) field1 почему-то
field1 between x and x согласно explain plan работает лучше (по стоимости) чем field1 = x.

Это фича такая о которой все знают, или просто локальная аномалия?

explain показывает план а не реальное время выполнения...
попробуйте explain analyze для начала
у меня получается
0.050ms для between
и
0.045ms для =
Цена планов равная в пределах погрешности.

--
Maxim Boguk
www.postgresql-consulting.ru
...
Рейтинг: 0 / 0
Between лучше Equal
    #38983037
Alex Marmuzevich
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ясно.
Под explain plan я имел ввиду выполнение EXPLAIN (ANALYZE on, VERBOSE off, COSTS on, BUFFERS off, TIMING on ) (т.е. с выполнеением запроса). И делал эта неоднократно.
И, раз уж для ответа на вопрос "фича, о которой все знают, или аномалия", то на всякий случай привожу детали:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
BEGIN;
EXPLAIN (ANALYZE on, VERBOSE off, COSTS on, BUFFERS off, TIMING on )select dmlp.id 
            FROM
              table1 dmlp
            WHERE  
             dmlp.field1 = 24251
;
ROLLBACK;

"Index Scan using idx_table1_field1 on table1 dmlp  (cost=0.00..2301.92 rows=1288 width=8) (actual time=23.188..2122.668 rows=3130 loops=1)"
"  Index Cond: (field1 = 24251)"
"Total runtime: 2125.363 ms"



Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
BEGIN;
EXPLAIN (ANALYZE on, VERBOSE off, COSTS on, BUFFERS off, TIMING on )select dmlp.id 
            FROM
              table1 dmlp
            WHERE  
             dmlp.field1 = 24251
;
ROLLBACK;

"Index Scan using idx_table1_field1 on table1 dmlp  (cost=0.00..2301.92 rows=1288 width=8) (actual time=23.188..2122.668 rows=3130 loops=1)"
"  Index Cond: (field1 = 24251)"
"Total runtime: 2125.363 ms"



Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
BEGIN;
EXPLAIN (ANALYZE on, VERBOSE off, COSTS on, BUFFERS off, TIMING on )select dmlp.id 
            FROM
              table1 dmlp
            WHERE  
             dmlp.field1 between 24251 and 24251
;
ROLLBACK;               

"Index Scan using idx_table1_field1 on table1 dmlp  (cost=0.00..5.08 rows=1 width=8) (actual time=0.054..11.177 rows=3130 loops=1)"
"  Index Cond: ((field1 >= 24251) AND (field1 <= 24251))"
"Total runtime: 15.219 ms"



Собственно таблица:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
CREATE TABLE table1
(
  id bigserial NOT NULL,
  some_id bigint NOT NULL,
  field1 bigint NOT NULL,
  CONSTRAINT table1_pkey PRIMARY KEY (id),
  CONSTRAINT fk_table1_some_id FOREIGN KEY (some_id)
      REFERENCES table2 (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT fk_table1_field1 FOREIGN KEY (field1)
      REFERENCES table3 (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
  OIDS=FALSE
);

CREATE INDEX idx_table1_some_id
  ON table1
  USING btree
  (some_id);

CREATE INDEX idx_table1_field1
  ON darbu_mokymo_lygiu_periodai
  USING btree
  (field1);



В таблице примерно 15 000 000 записей.

Похожее поведение видел и на других таблицах с другой структурой и другим количеством записей.
...
Рейтинг: 0 / 0
Between лучше Equal
    #38983041
Alex Marmuzevich
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да... Ожидалось то, что between будет или чуть медленее, или как-минимум такой же, как и equal. Но результат, когда between значительно быстрее чем простое сравнение несколько убил.
...
Рейтинг: 0 / 0
Between лучше Equal
    #38983078
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alex Marmuzevich,

результат интересный, но видимо вы что-то не так померяли

вот это вот смените на
Код: plaintext
BUFFERS oN

есть подозрение что вы таки на теплых данных мерили between , а на холодных -- все остальное

и побпробуйте явный каст к bigint. если это чудеса операторов-- надо посмотреть и в эту сторону (но в планах я подозрительного не вижу).

т.е. потщательнее бы, что ли.
...
Рейтинг: 0 / 0
Between лучше Equal
    #38983087
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
PS на 9.3.7. не воспроизводится

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
CREATE TABLE table1
(
  id bigserial NOT NULL,
  some_id bigint NOT NULL,
  field1 bigint NOT NULL,
  CONSTRAINT table1_pkey PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);

CREATE INDEX 
  ON table1
  USING btree
  (some_id);

CREATE INDEX 
  ON table1
  USING btree
  (field1);
-------------------------
INSERT INTO table1(
             some_id, field1)
SELECT i , k FROM generate_series(1,1000) i(i),generate_series(1,1000) k(k),generate_series(1,11) ;
---------------------------
EXPLAIN (ANALYZE on, VERBOSE off, COSTS on, BUFFERS on, TIMING on )
select dmlp.id FROM table1 dmlp
WHERE  dmlp.field1 = 242::bigint ;

'Bitmap Heap Scan on table1 dmlp  (cost=230.51..28673.93 rows=10590 width=8) (actual time=4.287..12.798 rows=11000 loops=1)'
'  Recheck Cond: (field1 = 242::bigint)'
'  Buffers: shared hit=11041'
'  ->  Bitmap Index Scan on table1_field1_idx  (cost=0.00..227.86 rows=10590 width=0) (actual time=2.061..2.061 rows=11000 loops=1)'
'        Index Cond: (field1 = 242::bigint)'
'        Buffers: shared hit=41'
'Total runtime: 13.297 ms'
-----------------------------------------
SET enable_bitmapscan TO oFF;
EXPLAIN (ANALYZE on, VERBOSE off, COSTS on, BUFFERS on, TIMING on )
select dmlp.id FROM table1 dmlp
WHERE  dmlp.field1 = 242::bigint ;

'Index Scan using table1_field1_idx on table1 dmlp  (cost=0.43..39715.32 rows=10590 width=8) (actual time=0.033..8.063 rows=11000 loops=1)'
'  Index Cond: (field1 = 242::bigint)'
'  Buffers: shared hit=11041'
'Total runtime: 8.709 ms'
-----------------------------------
EXPLAIN (ANALYZE on, VERBOSE off, COSTS on, BUFFERS on, TIMING on )
select dmlp.id FROM table1 dmlp
WHERE  dmlp.field1 >= 242::bigint AND dmlp.field1 <= 242::bigint ;

'Index Scan using table1_field1_idx on table1 dmlp  (cost=0.43..8.46 rows=1 width=8) (actual time=0.036..8.422 rows=11000 loops=1)'
'  Index Cond: ((field1 >= 242::bigint) AND (field1 <= 242::bigint))'
'  Buffers: shared hit=11041'
'Total runtime: 9.078 ms'

...
Рейтинг: 0 / 0
Between лучше Equal
    #38983090
Alexius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alex Marmuzevich,

есть подозрение на большой bloat в таблице/индексе, но как это влияет не очень понятно.
какой размер у индекса?

и можно привести explain обоих запросов (без analyze) с \timing on ? (звучит странно, но на всякий случай).

воспроизвести пока не удалось, у меня between чуть медленней всегда работает.
...
Рейтинг: 0 / 0
Between лучше Equal
    #38983095
Alex Marmuzevich
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Итак, ставим буфера (EXPLAIN (ANALYZE on, VERBOSE on, COSTS on, BUFFERS on, TIMING on ))
Получаем
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
"Index Scan using idx_table1_field1 on public.table1 dmlp  (cost=0.00..2301.92 rows=1288 width=8) (actual time=0.030..4.680 rows=3130 loops=1)"
"  Output: id"
"  Index Cond: (dmlp.field1 = 24251)"
"  Buffers: shared hit=2358"
"Total runtime: 6.634 ms"

"Index Scan using idx_table1_field1 on public.table1 dmlp  (cost=0.00..5.08 rows=1 width=8) (actual time=0.029..5.904 rows=3130 loops=1)"
"  Output: id"
"  Index Cond: ((dmlp.field1 >= 24251) AND (dmlp.field1 <= 24251))"
"  Buffers: shared hit=2358"
"Total runtime: 7.761 ms"

"Index Scan using idx_table1_field1 on public.table1 dmlp  (cost=0.00..2301.92 rows=1288 width=8) (actual time=0.039..5.601 rows=3130 loops=1)"
"  Output: id"
"  Index Cond: (dmlp.field1 = 24251)"
"  Buffers: shared hit=2358"
"Total runtime: 7.603 ms"


(Специально прогнал equal запрос дважды).

Инфа по таблице:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
Последовательных проходов	13	
Кортежей считанных последователь	178250367	
Проходов по индексу	600122	
Кортежей извлечено	998212	
Кортежей добавлено	5	
Кортежей обновлено	361	
Кортежей удалено	0	
Кортежей обновлено онлайн	0	
Кортежей доступно	14813166	
«Мертвых» кортежей	0	
Heap-блоков прочитано	1855348	
Heap-блоков пройдено	731477	
Блоков прочитано	288567	
Блоков пройдено	1641793	
Toast-блоков прочитано		
Toast-блоков пройдено		
Индексных toast-блоков прочитано		
Индексных toast-блоков пройдено		
Последняя очистка	2015-06-12 10:59:27.925109+03	
Последняя автоочистка		
Последний анализ	2015-06-12 10:59:28.219949+03	
Последний автоанализ		
Счётчик очистки	1	
Счётчик автоочистки	0	
Счётчик анализа	1	
Счётчик автоанализа	0	
Размер таблицы	906 MB	
Размер таблицы Toast	нет	
Размер индексов	954 MB


Информация по индексу
Код: sql
1.
2.
3.
4.
5.
6.
Проходов по индексу	563	
Кортежей прочитано	360386	
Кортежей извлечено	356765	
Блоков прочитано	41418	
Блоков пройдено	3389	
Размер индекса	318 MB
...
Рейтинг: 0 / 0
Between лучше Equal
    #38983097
Alex Marmuzevich
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AlexiusAlex Marmuzevich,

есть подозрение на большой bloat в таблице/индексе, но как это влияет не очень понятно.
какой размер у индекса?

и можно привести explain обоих запросов (без analyze) с \timing on ? (звучит странно, но на всякий случай).

воспроизвести пока не удалось, у меня between чуть медленней всегда работает.
Э... как-бы EXPLAIN option TIMING requires ANALYZE... Или имелось ввиду что-то другое?
...
Рейтинг: 0 / 0
Between лучше Equal
    #38983101
Alexius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alex Marmuzevich,

хм, а в приведенных планах то разницы во времени выполнения не видно той, которая была. может на холодных данных первый запрос выполнялся?

имелось ввиду \timing в psql, чтобы посмотреть время выполнения самого explain, но тут похоже это не оно. размер индекса нормальный для такой таблицы.
...
Рейтинг: 0 / 0
Between лучше Equal
    #38983108
Alex Marmuzevich
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AlexiusAlex Marmuzevich,

хм, а в приведенных планах то разницы во времени выполнения не видно той, которая была. может на холодных данных первый запрос выполнялся?

имелось ввиду \timing в psql, чтобы посмотреть время выполнения самого explain, но тут похоже это не оно. размер индекса нормальный для такой таблицы.
На каких холодных? Делаю запрос. Возвращается примерно 3500 записей за 62 ms. Строю план (см выше). Меняю параметры. Делаю запрос - скорость примерно такая же. Строю план - стоимость как скала. Поведение equal-between - не изменяется. Тут скорее получаем что данные горячие. Вроде слухи ходили, что после перезапуска сервера запрос примерно 60 секунд выполнялся, но проверить не могу (нет возможности перезагрузить сервер). Ради интереса сделал discard all, но это ни на что не повлияло.
...
Рейтинг: 0 / 0
Between лучше Equal
    #38983110
Alex Marmuzevich
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кстати, explain в среднем выполняется за 60-80 ms.
...
Рейтинг: 0 / 0
Between лучше Equal
    #38983114
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AlexiusAlex Marmuzevich,

хм, а в приведенных планах то разницы во времени выполнения не видно той, которая была. может на холодных данных первый запрос выполнялся?

имелось ввиду \timing в psql, чтобы посмотреть время выполнения самого explain, но тут похоже это не оно. размер индекса нормальный для такой таблицы.
ну да, разницы то теперь никакой.

но тс закусил удила. уже невменяем, похоже.
...
Рейтинг: 0 / 0
13 сообщений из 13, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Between лучше Equal
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]