powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Помогите с запросом - сколько раз в неделю
25 сообщений из 25, страница 1 из 1
Помогите с запросом - сколько раз в неделю
    #39212530
Perederiy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
имеется таблица с более 20 млн записями

name (text). date(datetime)

надо выбрать значение name которые встречаются БОЛЕЕ 1 РАЗА В НЕДЕЛЮ
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39212546
fortress
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Примерно так:

CREATE TABLE worktime
(
name text,
dt timestamp with time zone
)
WITH (
OIDS=FALSE
);
ALTER TABLE worktime
OWNER TO postgres;

select name,count(extract(week from dt)) from worktime
group by name,extract(week from dt)
having count(extract(week from dt))>1


PS. я только учусь.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39212548
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Perederiy,

Для начала определите понятие недели.

--
Maxim Boguk
www.postgresql-consulting.ru
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39212563
Perederiy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Maxim BogukPerederiy,

Для начала определите понятие недели.

--
Maxim Boguk
www.postgresql-consulting.ru

понедельник-воскресенье
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39213010
Фотография Щукина Анна
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fortress,

На 20 млн. данных Тс рискует не дождаться результата выполнения запроса.
Возможно, логичнее было бы использовать [not]exists-подзапрос или самообъединение таблицы...
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39213341
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Щукина Аннаfortress,

На 20 млн. данных Тс рискует не дождаться результата выполнения запроса.
Возможно, логичнее было бы использовать [not]exists-подзапрос или самообъединение таблицы...
если узкая таблица из двух полей - вполне фулскан справиться.
А вот джоин сам на себя приведет только к двуктратному ухудшению.
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39213378
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ivan DurakЩукина Аннаfortress,

На 20 млн. данных Тс рискует не дождаться результата выполнения запроса.
Возможно, логичнее было бы использовать [not]exists-подзапрос или самообъединение таблицы...
если узкая таблица из двух полей - вполне фулскан справиться.
А вот джоин сам на себя приведет только к двуктратному ухудшению.а агрегаты бесплатно деются, ага

де'биллы, ять.

какой нахер джойн, если есть индекс, по которому сиком можно проверить наличие в диапазоне ?

де'биллы, ять.

тут ещё икстендер такой пасётся -- чуть что чушь несёт про "двойное обращение к таблице"

де'билл, ять.


при малости числа name относительно этих 20 лямов -- задача вообще вырождается в пародию на луз--индекскан.
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39213884
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwqIvan Durakпропущено...

если узкая таблица из двух полей - вполне фулскан справиться.
А вот джоин сам на себя приведет только к двуктратному ухудшению.а агрегаты бесплатно деются, ага

де'биллы, ять.

какой нахер джойн, если есть индекс, по которому сиком можно проверить наличие в диапазоне ?

де'биллы, ять.

тут ещё икстендер такой пасётся -- чуть что чушь несёт про "двойное обращение к таблице"

де'билл, ять.


при малости числа name относительно этих 20 лямов -- задача вообще вырождается в пародию на луз--индекскан.
сколько у тебя сиков будет? 20 лямов?
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39214147
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ivan Durakqwwqпропущено...
при малости числа name относительно этих 20 лямов -- задача вообще вырождается в пародию на луз--индекскан.
сколько у тебя сиков будет? 20 лямов?
вам какую аценку, радной?

пессимистическую --- вы само сделало , только 2--ку забыло.

оптимистическая -- count(DISTINCT name) *2

обе оценки тривиальны. но истина -- она где--то между, ага.
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39215278
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwqIvan Durakпропущено...

сколько у тебя сиков будет? 20 лямов?
вам какую аценку, радной?

пессимистическую --- вы само сделало , только 2--ку забыло.

оптимистическая -- count(DISTINCT name) *2

обе оценки тривиальны. но истина -- она где--то между, ага.
оптимистическая неверна.
Если у тебя даже 1 товар всего, но 100500 разных недель.... сиков будет ни разу не два
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39215372
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2Дурак

учимся читать:
Perederiyимеется таблица с более 20 млн записями

name (text). date(datetime)

надо выбрать значение name которые встречаются БОЛЕЕ 1 РАЗА В НЕДЕЛЮ

ни разу не сказано что надо выбрать {имена "и недели"}.

т.ч. засуньте своё мнение по адресу произрастания ваших рук. Достаточно чтобы всё сошлось на первой же неделе для каждого имени. точка.

// я к тому, что к "коду начинающего" выше по треду надо добавить DISTINCT в исходной постановке, или изменить постановку. (второе так же вероятно, ибо пассажыр известен неточностями. но пока -- решать надо так, как сформулировано).
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39215594
fortress
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Щукина Аннаfortress,

На 20 млн. данных Тс рискует не дождаться результата выполнения запроса.
Возможно, логичнее было бы использовать [not]exists-подзапрос или самообъединение таблицы...

Никак не могу придумать такой запрос с предикатом exists: он же true когда что-то есть в подзапросе и false - когда ничего нет. А здесь условие чтобы количество в неделю было больше одного. Или имелось ввиду в подзапросе для exist считать количество попаданий в неделю? Тогда чем это лучше group by/having?
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39215615
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fortressЩукина Аннаfortress,

На 20 млн. данных Тс рискует не дождаться результата выполнения запроса.
Возможно, логичнее было бы использовать [not]exists-подзапрос или самообъединение таблицы...

Никак не могу придумать такой запрос с предикатом exists: он же true когда что-то есть в подзапросе и false - когда ничего нет. А здесь условие чтобы количество в неделю было больше одного. Или имелось ввиду в подзапросе для exist считать количество попаданий в неделю? Тогда чем это лучше group by/having?

для простоты, чтобы не реализовывать loose--indexscan руками, представим, что у вас есть головная [reference] таблица names

тогда запрос ~

Код: sql
1.
2.
3.
4.
SELECT name FROM names
 WHERE EXISTS (SELECT запись 1 из таблицы, с тем же name, для которой EXIST
           (запись 2 из таблицы с тем же именем, и датой, в пределах недели от записи 1, отличная от записи 1)
)


зачем вам весь каунт (да ещё по всем неделям), когда вас интересует наличие [не менее] 2--х (хоть в какой--то неделе) ?

в случае отсутствия -- первый экзист солется в экстазе с WITH recursive реализацией loose indexscan--а.
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39216477
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwqfortressпропущено...


Никак не могу придумать такой запрос с предикатом exists: он же true когда что-то есть в подзапросе и false - когда ничего нет. А здесь условие чтобы количество в неделю было больше одного. Или имелось ввиду в подзапросе для exist считать количество попаданий в неделю? Тогда чем это лучше group by/having?

для простоты, чтобы не реализовывать loose--indexscan руками, представим, что у вас есть головная [reference] таблица names

тогда запрос ~

Код: sql
1.
2.
3.
4.
SELECT name FROM names
 WHERE EXISTS (SELECT запись 1 из таблицы, с тем же name, для которой EXIST
           (запись 2 из таблицы с тем же именем, и датой, в пределах недели от записи 1, отличная от записи 1)
)


зачем вам весь каунт (да ещё по всем неделям), когда вас интересует наличие [не менее] 2--х (хоть в какой--то неделе) ?

в случае отсутствия -- первый экзист солется в экстазе с WITH recursive реализацией loose indexscan--а.
план если не лень будет проверю, но имхо там фулскан на первом же экзисте
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39217936
fortress
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Попробовал 2 способами: через exist и через having.
Таблица (индексов по полям нет):
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
CREATE TABLE tlog
(
  id serial NOT NULL,
  num character(9),
  dt timestamp without time zone,
  CONSTRAINT pk_id PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);



Запрос 1:
Код: sql
1.
2.
3.
4.
select num
from tlog
group by num,extract(week from dt),extract(year from dt)
having count(extract(week from dt))>1


План:
"GroupAggregate (cost=147906.84..180406.84 rows=1000000 width=18) (actual time=11305.775..15200.587 rows=146 loops=1)"
" Group Key: num, (date_part('week'::text, dt)), (date_part('year'::text, dt))"
" Filter: (count((date_part('week'::text, dt))) > 1)"
" Rows Removed by Filter: 999708"
" -> Sort (cost=147906.84..150406.84 rows=1000000 width=18) (actual time=11301.042..14561.973 rows=1000000 loops=1)"
" Sort Key: num, (date_part('week'::text, dt)), (date_part('year'::text, dt))"
" Sort Method: external merge Disk: 48784kB"
" -> Seq Scan on tlog (cost=0.00..27739.00 rows=1000000 width=18) (actual time=26.221..1149.959 rows=1000000 loops=1)"
"Planning time: 0.092 ms"
"Execution time: 15208.465 ms"
Код: sql
1.
2.
"Planning time: 0.092 ms"
"Execution time: 15208.465 ms"


Запрос 2:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
select num
from tlog t1
where
exists(
    select num from tlog t2
    where
    t2.num=t1.num
    and t2.id<>t1.id
    and t2.dt > t1.dt
    and date_part('year',t1.dt)*date_part('week',t1.dt)-date_part('year',t2.dt)*date_part('week',t2.dt) = 0
)



План:
"Hash Semi Join (cost=41099.00..84418.00 rows=1 width=10) (actual time=789.367..2305.005 rows=146 loops=1)"
" Hash Cond: (t1.num = t2.num)"
" Join Filter: ((t2.id <> t1.id) AND (t2.dt > t1.dt) AND (((date_part('year'::text, t1.dt) * date_part('week'::text, t1.dt)) - (date_part('year'::text, t2.dt) * date_part('week'::text, t2.dt))) = 0::double precision))"
" Rows Removed by Join Filter: 1057103"
" -> Seq Scan on tlog t1 (cost=0.00..22739.00 rows=1000000 width=22) (actual time=26.454..240.050 rows=1000000 loops=1)"
" -> Hash (cost=22739.00..22739.00 rows=1000000 width=22) (actual time=682.298..682.298 rows=1000000 loops=1)"
" Buckets: 16384 Batches: 16 Memory Usage: 2953kB"
" -> Seq Scan on tlog t2 (cost=0.00..22739.00 rows=1000000 width=22) (actual time=25.716..234.652 rows=1000000 loops=1)"
"Planning time: 0.357 ms"
"Execution time: 2306.248 ms"
Код: sql
1.
2.
"Planning time: 0.357 ms"
"Execution time: 2306.248 ms"



Запросы выполнялись один за другим (несколько раз), поэтому кеш тоже как-то оказвает влияние.
Про использование exist сразу не додумался, но qwwq подсказал, в результате получился второй запрос.
На что нужно обратить внимание:
группировать нужно еще и по годам, т.к. номер недели будет уникальным только в
пределах одного года;

записи на границе годов;
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39218231
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ну добавь индекс то по наме+дата
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39220692
fortress
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добавил индексы
Код: 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.
CREATE TABLE tlog
(
  num character varying(9),
  dt timestamp without time zone,
  id serial NOT NULL,
  CONSTRAINT tlog_pkey PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE tlog
  OWNER TO ivan;

-- Index: tlog_dt

-- DROP INDEX tlog_dt;

CREATE INDEX tlog_dt
  ON tlog
  USING btree
  (dt);

-- Index: tlog_num

-- DROP INDEX tlog_num;

CREATE INDEX tlog_num
  ON tlog
  USING btree
  (num COLLATE pg_catalog."default");



Результаты не сильно изменились.
Код: sql
1.
2.
3.
4.
select num
from tlog
group by num,extract(week from dt),extract(year from dt)
having count(extract(week from dt))>1


"GroupAggregate (cost=163030.96..195531.00 rows=1000001 width=17) (actual time=9287.012..11121.720 rows=154 loops=1)"
" Filter: (count((date_part('week'::text, dt))) > 1)"
" -> Sort (cost=163030.96..165530.97 rows=1000001 width=17) (actual time=9277.208..10654.634 rows=1000005 loops=1)"
" Sort Key: num, (date_part('week'::text, dt)), (date_part('year'::text, dt))"
" Sort Method: external merge Disk: 48856kB"
" -> Seq Scan on tlog (cost=0.00..22353.02 rows=1000001 width=17) (actual time=0.063..801.386 rows=1000005 loops=1)"
"Total runtime: 11129.723 ms"

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
select num
from tlog t1
where
exists(
    select num from tlog t2
    where
    t2.num=t1.num
    and t2.id<>t1.id
    and t2.dt > t1.dt
    and date_part('year',t1.dt)*date_part('week',t1.dt)-date_part('year',t2.dt)*date_part('week',t2.dt) = 0
)


"Hash Semi Join (cost=35713.02..74146.04 rows=1 width=9) (actual time=1167.768..3047.378 rows=154 loops=1)"
" Hash Cond: ((t1.num)::text = (t2.num)::text)"
" Join Filter: ((t2.id <> t1.id) AND (t2.dt > t1.dt) AND (((date_part('year'::text, t1.dt) * date_part('week'::text, t1.dt)) - (date_part('year'::text, t2.dt) * date_part('week'::text, t2.dt))) = 0::double precision))"
" -> Seq Scan on tlog t1 (cost=0.00..17353.01 rows=1000001 width=21) (actual time=0.062..216.557 rows=1000005 loops=1)"
" -> Hash (cost=17353.01..17353.01 rows=1000001 width=21) (actual time=1011.997..1011.997 rows=1000005 loops=1)"
" Buckets: 2048 Batches: 64 Memory Usage: 870kB"
" -> Seq Scan on tlog t2 (cost=0.00..17353.01 rows=1000001 width=21) (actual time=0.004..211.858 rows=1000005 loops=1)"
"Total runtime: 3047.731 ms"


Похоже что индексы не используются, т.к. в планах оcтался Seq Scan. Ведь должен быть Index Scan?
Это такие запросы, которые не могут использовать индексы, или такие индексы, которые не могут быть использованы в этих запросах?
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39220714
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fortress<>
Это такие запросы, которые не могут использовать индексы, или такие индексы, которые не могут быть использованы в этих запросах?и то и другое

для нахождения существования второго факта в пределах недели от первого нет нужды сначала множится на все факты отличные от текущего , а потом фильтровать по заумным функциональным выражениям.

достаточно посмотреть на следующий факт вдоль подходящего индекса в диапазоне не более 8 дней и убедиться в том , что он не вывалился из нашей недели. или наоборот -- вывалился.
как--то так.

подходящим будет составной индекс по нейму и дате, и именно в таком порядке.
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39220719
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
или что следующего, в пределе 8 дней, -- нет.
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39221921
fortress
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwqдля нахождения существования второго факта в пределах недели от первого нет нужды сначала множится на все факты отличные от текущего , а потом фильтровать по заумным функциональным выражениям.
достаточно посмотреть на следующий факт вдоль подходящего индекса в диапазоне не более 8 дней и убедиться в том , что он не вывалился из нашей недели. или наоборот -- вывалился.
ТС вроде обмолвился что неделя у него это понедельник-воскресенье, как я понял календарная неделя. Если разница межу 2 событиями менее 8 дней, то это не значит, что они в пределах одной и той же календарной недели. В моей тестовой БД из 1 млн. строк записи за несколько лет, поэтому приходится учитывать ещё и год. Отсюда такое выражение.
Можно, конечно, и так переписать:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
select num
from tlog t1
where
exists(
    select num from tlog t2
    where
    t2.num=t1.num
    and t2.id<>t1.id
    and t2.dt > t1.dt
    and date_part('year',t1.dt) = date_part('year',t2.dt)
    and date_part('week',t1.dt) = date_part('week',t2.dt)
)
order by dt


qwwqподходящим будет составной индекс по нейму и дате, и именно в таком порядке.
Попробовал создать индекс:
Код: sql
1.
2.
3.
4.
CREATE INDEX tlog_num_dt_idx
  ON tlog
  USING btree
  (num COLLATE pg_catalog."default", dt);


Для этого
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
select num
from tlog t1
where
exists(
    select num from tlog t2
    where
    t2.num=t1.num
    and t2.id<>t1.id
    and t2.dt > t1.dt
    and date_part('year',t1.dt)*date_part('week',t1.dt)-date_part('year',t2.dt)*date_part('week',t2.dt)=0
    )
order by dt


запроса в плане отсутствует упоминание об использовании индексов:
"Sort (cost=74146.19..74146.19 rows=1 width=17) (actual time=26468.490..26468.496 rows=154 loops=1)"
" Sort Key: t1.dt"
" Sort Method: quicksort Memory: 37kB"
" -> Hash Semi Join (cost=35713.11..74146.18 rows=1 width=17) (actual time=10368.299..26468.155 rows=154 loops=1)"
" Hash Cond: ((t1.num)::text = (t2.num)::text)"
" Join Filter: ((t2.id <> t1.id) AND (t2.dt > t1.dt) AND (((date_part('year'::text, t1.dt) * date_part('week'::text, t1.dt)) - (date_part('year'::text, t2.dt) * date_part('week'::text, t2.dt))) = 0::double precision))"
" -> Seq Scan on tlog t1 (cost=0.00..17353.05 rows=1000005 width=21) (actual time=0.031..220.269 rows=1000005 loops=1)"
" -> Hash (cost=17353.05..17353.05 rows=1000005 width=21) (actual time=10172.847..10172.847 rows=1000005 loops=1)"
" Buckets: 2048 Batches: 64 Memory Usage: 870kB"
" -> Seq Scan on tlog t2 (cost=0.00..17353.05 rows=1000005 width=21) (actual time=0.004..211.227 rows=1000005 loops=1)"
"Total runtime: 26468.760 ms"


Также время выполнения запроса выросло в 10 раз со вчерашнего дня, с чем связано - не знаю. Пробовал созданный индекс удалять - не помогло. Больше с базой ничего не делал.
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39221964
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fortressqwwqдля нахождения существования второго факта в пределах недели от первого нет нужды сначала множится на все факты отличные от текущего , а потом фильтровать по заумным функциональным выражениям.
достаточно посмотреть на следующий факт вдоль подходящего индекса в диапазоне не более 8 дней и убедиться в том , что он не вывалился из нашей недели. или наоборот -- вывалился.
ТС вроде обмолвился что неделя у него это понедельник-воскресенье, как я понял календарная неделя. Если разница межу 2 событиями менее 8 дней, то это не значит, что они в пределах одной и той же календарной недели.

я не совсем понимаю, вы прикидываетесь, или всё действительно так плохо.

ещё раз , добавьте условие , что следующее искомое ищется в диапазоне не более 8 дней. И (AND) какое угодно замысловатое условие фильтра на вашу любимую "ту же неделю".

условие про 8 дней нужно чтобы обрезать оптимайзеру область поиска. и счета
вы же не думаете, что у ней унутре неонка и думатель.

вот чтобы 20 миллионов раз не молотить чиселки в холостую, а до того -- не читать их с диска или кеша -- обрежьте, ять, вдоль индекса. (там, при прямой навигации нужен один seek и проверка -- и всё, больше там ничего не надо)

что-то типа
Код: sql
1.
AND (SELECT dat FROM ... WHERE {в 8ми днях от опорной} order by dat limit 1) E {неделя от опорной}



ну и вообще говоря у меня нет уверенности, что если мы таки не вернемся к тому, что в постановке не требуется выводить нейм столько раз , сколько подходящих недель -- то полуцчим реальный выигрыш. но это отдельный разговор про with recursive реализацию loose indexscan--а. и оценки распределения.
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39222005
Lonepsycho
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwq,

а делать индех по EXTRACT(WEEK FROM timestampfield); и делать поиск недели по этому выражению? не?
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39222025
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Lonepsychoqwwq,

а делать индех по EXTRACT(WEEK FROM timestampfield); и делать поиск недели по этому выражению? не?ыыыЫ?

кю

повторяю:
вам надо посмотреть на первый лист индекса , обычного индекса по таймтстампу, и всё. никакого поиска недели не надо. лист либо лежит в той же неделе, либо не судьба.

и тогда это превратится в 20 лямов сиков, как метко заметил Ваня дурак. а вот когда мы заметим, что мы имя выводим столько раз , сколько таких недель, а нас просили вывести один -- вот тогда начнётся (от распределения) экономия. если сумеем аккуратно записать обход с отбрасыванием.
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39222029
Lonepsycho
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwqповторяю:
вам надо посмотреть на первый лист индекса , обычного индекса по таймтстампу, и всё. никакого поиска недели не надо. лист либо лежит в той же неделе, либо не судьба.

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

я это понял, но идея была не искать существуют ли даты на дистанции 8 дней, а искать существуют ли даты попадающие в одну и ту же самую неделю (более дёшиво чтоли). однако да. ф-я week работает в пределах одного года (и в пересечениях лет), и, результат не является уникальным для епохи. так что может идея и не правильная.
...
Рейтинг: 0 / 0
Помогите с запросом - сколько раз в неделю
    #39222491
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
подытожу, о чём примерно шла речь:

подготовка кейса
DDL:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
CREATE TABLE tlog
(
	id serial NOT NULL,
	num character(9)	NOT NULL,
	dt timestamp without time zone NOT NULL,
	PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);

CREATE INDEX
  ON tlog
  USING btree
  (num, dt);


--DATA:
Код: 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.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
BEGIN;
TRUNCATE tlog;
END;
BEGIN;
INSERT INTO tlog(num, dt)
SELECT trim(n::text ) , date'2013-01-01' + (random()*d*10 )::integer
FROM 
	generate_series(1, 10000) n
	,generate_series(1, 200) d;
END;
BEGIN;
INSERT INTO tlog(num, dt)
SELECT trim(n::text ) , date'2013-01-01' + (random()*d*10 )::integer
FROM 
	generate_series(1, 10000) n
	,generate_series(1, 200) d;
END;
BEGIN;
INSERT INTO tlog(num, dt)
SELECT trim(n::text ) , date'2013-01-01' + (random()*d*10 )::integer
FROM 
	generate_series(1, 10000) n
	,generate_series(1, 200) d;
END;
BEGIN;
INSERT INTO tlog(num, dt)
SELECT trim(n::text ) , date'2013-01-01' + (random()*d*10 )::integer
FROM 
	generate_series(1, 10000) n
	,generate_series(1, 200) d;
END;
BEGIN;
INSERT INTO tlog(num, dt)
SELECT trim(n::text ) , date'2013-01-01' + (random()*d*10 )::integer
FROM 
	generate_series(1, 10000) n
	,generate_series(1, 200) d;
END;
BEGIN;
INSERT INTO tlog(num, dt)
SELECT trim(n::text ) , date'2013-01-01' + (random()*d*10 )::integer
FROM 
	generate_series(1, 10000) n
	,generate_series(1, 200) d;
END;
BEGIN;
INSERT INTO tlog(num, dt)
SELECT trim(n::text ) , date'2013-01-01' + (random()*d*10 )::integer
FROM 
	generate_series(1, 10000) n
	,generate_series(1, 200) d;
END;
BEGIN;
INSERT INTO tlog(num, dt)
SELECT trim(n::text ) , date'2013-01-01' + (random()*d*10 )::integer
FROM 
	generate_series(1, 10000) n
	,generate_series(1, 200) d;
END;
BEGIN;
INSERT INTO tlog(num, dt)
SELECT trim(n::text ) , date'2013-01-01' + (random()*d*10 )::integer
FROM 
	generate_series(1, 10000) n
	,generate_series(1, 200) d;
END;
BEGIN;
INSERT INTO tlog(num, dt)
SELECT trim(n::text ) , date'2013-01-01' + (random()*d*10 )::integer
FROM 
	generate_series(1, 10000) n
	,generate_series(1, 200) d;
END;
BEGIN;
ANALYZE tlog;
END;



планы :
GROUP
Код: sql
1.
2.
3.
4.
select num
from tlog
group by num,extract(week from dt),extract(year from dt)
having count(extract(week from dt))>1


Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
GroupAggregate  (cost=3673065.00..4008066.22 rows=2000008 width=18) (actual time=312409.734..403131.516 rows=2197589 loops=1)
  Output: num, (date_part('week'::text, dt)), (date_part('year'::text, dt))
  Filter: (count((date_part('week'::text, tlog.dt))) > 1)
  Rows Removed by Filter: 319805
  Buffers: shared hit=13750 read=113639, temp read=163178 written=163178
  ->  Sort  (cost=3673065.00..3723065.18 rows=20000072 width=18) (actual time=312217.935..393348.149 rows=20000000 loops=1)
        Output: num, (date_part('week'::text, dt)), (date_part('year'::text, dt)), dt
        Sort Key: tlog.num, (date_part('week'::text, tlog.dt)), (date_part('year'::text, tlog.dt))
        Sort Method: external merge  Disk: 977472kB
        Buffers: shared hit=13750 read=113639, temp read=163178 written=163178
        ->  Seq Scan on public.tlog  (cost=0.00..427390.08 rows=20000072 width=18) (actual time=0.031..112665.319 rows=20000000 loops=1)
              Output: num, date_part('week'::text, dt), date_part('year'::text, dt), dt
              Buffers: shared hit=13750 read=113639
Total runtime: 404599.624 ms



//на distinct забиваем


LOOSE--INDEXSCAN
Код: 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.
WITH RECURSIVE rt AS
(
	(select t1.num
	from tlog t1
	where
	(
		select date_part('week',t2.dt) from tlog t2
		where
		t2.num=t1.num
		and t2.id<>t1.id
		and t2.dt > t1.dt
		and t2.dt <= t1.dt::date +8
		ORDER BY t2.num, t2.dt LIMIT 1
	)
	= date_part('week',t1.dt)
	ORDER BY t1.num, t1.dt LIMIT 1)
UNION ALL 
	(select t1.num
	from rt
	,LATERAL (SELECT num FROM tlog t1 
		where
			t1.num>rt.num
		AND (
			select date_part('week',t2.dt) from tlog t2
			where
				t1.num>rt.num
			AND t2.num=t1.num
			and t2.id<>t1.id
			and t2.dt > t1.dt
			and t2.dt <= t1.dt::date +8
			ORDER BY t2.num, t2.dt LIMIT 1
		)
		= date_part('week',t1.dt)

		ORDER BY t1.num, t1.dt LIMIT 1) t1

	)
)
SELECT * FROM rt --LIMIT 10000


Код: 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.
CTE Scan on rt  (cost=176393.33..176395.35 rows=101 width=40) (actual time=0.116..100131.760 rows=10000 loops=1)
  Output: rt.num
  Buffers: shared hit=74285 read=25749
  CTE rt
    ->  Recursive Union  (cost=0.56..176393.33 rows=101 width=18) (actual time=0.114..100122.313 rows=10000 loops=1)
          Buffers: shared hit=74285 read=25749
          ->  Subquery Scan on "*SELECT* 1"  (cost=0.56..1745.39 rows=1 width=18) (actual time=0.113..0.114 rows=1 loops=1)
                Output: "*SELECT* 1".num
                Buffers: shared hit=8 read=2
                ->  Limit  (cost=0.56..1745.38 rows=1 width=18) (actual time=0.112..0.112 rows=1 loops=1)
                      Output: t1.num, t1.dt
                      Buffers: shared hit=8 read=2
                      ->  Index Scan using tlog_num_dt_idx on public.tlog t1  (cost=0.56..174481850.39 rows=100000 width=18) (actual time=0.111..0.111 rows=1 loops=1)
                            Output: t1.num, t1.dt
                            Filter: ((SubPlan 1) = date_part('week'::text, t1.dt))
                            Buffers: shared hit=8 read=2
                            SubPlan 1
                              ->  Limit  (cost=0.57..4.94 rows=1 width=18) (actual time=0.041..0.042 rows=1 loops=1)
                                    Output: (date_part('week'::text, t2.dt)), t2.num, t2.dt
                                    Buffers: shared hit=5
                                    ->  Index Scan using tlog_num_dt_idx on public.tlog t2  (cost=0.57..48.70 rows=11 width=18) (actual time=0.033..0.033 rows=1 loops=1)
                                          Output: date_part('week'::text, t2.dt), t2.num, t2.dt
                                          Index Cond: ((t2.num = t1.num) AND (t2.dt > t1.dt) AND (t2.dt <= ((t1.dt)::date + 8)))
                                          Filter: (t2.id <> t1.id)
                                          Buffers: shared hit=5
          ->  Nested Loop  (cost=0.56..17464.59 rows=10 width=10) (actual time=10.009..10.010 rows=1 loops=10000)
                Output: t1_1.num
                Buffers: shared hit=74277 read=25747
                ->  WorkTable Scan on rt rt_1  (cost=0.00..0.20 rows=10 width=40) (actual time=0.000..0.001 rows=1 loops=10000)
                      Output: rt_1.num
                ->  Limit  (cost=0.56..1746.42 rows=1 width=18) (actual time=10.008..10.008 rows=1 loops=10000)
                      Output: t1_1.num, t1_1.dt
                      Buffers: shared hit=74277 read=25747
                      ->  Index Scan using tlog_num_dt_idx on public.tlog t1_1  (cost=0.56..58194644.09 rows=33333 width=18) (actual time=10.006..10.006 rows=1 loops=10000)
                            Output: t1_1.num, t1_1.dt
                            Index Cond: (t1_1.num > rt_1.num)
                            Filter: ((SubPlan 2) = date_part('week'::text, t1_1.dt))
                            Buffers: shared hit=74277 read=25747
                            SubPlan 2
                              ->  Limit  (cost=0.57..4.95 rows=1 width=18) (actual time=1.421..1.421 rows=1 loops=9999)
                                    Output: (date_part('week'::text, t2_1.dt)), t2_1.num, t2_1.dt
                                    Buffers: shared hit=42802 read=7201
                                    ->  Result  (cost=0.57..48.71 rows=11 width=18) (actual time=1.420..1.420 rows=1 loops=9999)
                                          Output: date_part('week'::text, t2_1.dt), t2_1.num, t2_1.dt
                                          One-Time Filter: (t1_1.num > $5)
                                          Buffers: shared hit=42802 read=7201
                                          ->  Index Scan using tlog_num_dt_idx on public.tlog t2_1  (cost=0.57..48.68 rows=11 width=18) (actual time=1.414..1.414 rows=1 loops=9999)
                                                Output: t2_1.id, t2_1.num, t2_1.dt
                                                Index Cond: ((t2_1.num = t1_1.num) AND (t2_1.dt > t1_1.dt) AND (t2_1.dt <= ((t1_1.dt)::date + 8)))
                                                Filter: (t2_1.id <> t1_1.id)
                                                Buffers: shared hit=42802 read=7201
Total runtime: 100135.295 ms




резюме : при count(distinct name) < 1/2000 от count(1) имеет смысл LOOSE indexscan. (время у него, навскидку, в этой задаче зависит от распределения, а минимум -- только от этого отношения -- для каждого нейм -- 2 сика. и либо пан, либо нет.
если же распределение хуже -- число сиков будет расти с переходом в пределе к пресловутым "20 лямам"*2)

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


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