powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Кто сталкивался с такой задачей, помогите!
4 сообщений из 4, страница 1 из 1
Кто сталкивался с такой задачей, помогите!
    #34601201
Teccilla
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Задача такая, есть например таблица юзеров, состоящая из 10 миллионов записей.. У каждого юзера есть поле, в котором хранится скажем уникальное целое число, указывающее на кол-во баллов.
Задача при выборе данных пользователя определить на каком месте он находится в общем списке всех пользователей по этому баллу, НЕ ИСПОЛЬЗУЯ в подзапросе COUNT..
То есть просто это
SELECT
u.name, u.scores,
(SELECT COUNT(id) FROM users WHERE scores>=p.scores) AS rank
FROM users
WHERE id=3256

Но учитывая объем таблицы и то, что count довольно трудоемкая операция - этот вариант не прокатывает..

Подскажите, как это можно обойти, может какое-то gist-расширение свое написать, или индекс свой, в общем ПОМОГИТЕ! Заранее благодарен.
...
Рейтинг: 0 / 0
Кто сталкивался с такой задачей, помогите!
    #34601652
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
TeccillaУ каждого юзера есть поле, в котором хранится скажем уникальное целое число, указывающее на кол-во баллов.Действительно ли кол-во баллов уникально, то есть не может быть двух юзеров с одинаковым кол-вом баллов? Если да, то благодаря чему это имеет место, то есть как именно изменяется кол-во баллов? Может быть в этом случае получиться сделать триггер на некое поле "место юзера".
...
Рейтинг: 0 / 0
Кто сталкивался с такой задачей, помогите!
    #34601996
Teccilla
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Уникальность просто для упрощения задачи, скажем в дейтинге при поднятии анкеты наверх туда пишется время поднятия с учетом миллисекунд - этого в принципе достаточно чтобы уникальность сохранить.. Но это опять же только для примера..

Если вводить какое-то поле, которое указывало бы на место, то получится, что нужно будет не только его апдейтить при изменении, а всех кого измененная позиция затрагивает, то есть если я был на месте 1000000 а стал на первых, надо сместить всех с первого по миллион на единицу вниз, а это нереально при таких объемах данных..

Пока в принципе это реализовано отдельной таблицей, скажем ranks (id serial, uid)
и периодически выполняются следующие операции:
- Очищаем таблицу ranks
- Устанавливаем текущее значение последовательности ranks_id_seq в 1.
- Вставляем в таблицу ranks выборку из таблицы users, отсортированную по scores DESC
В итоге получаем новую таблицу ranks где id - указывает на позицию в листинге юзера с uid, и при выборке данных из юзеров через LEFT JOIN ranks по uid получаем его позицию..

Но хочется более красивого решения:)
...
Рейтинг: 0 / 0
Кто сталкивался с такой задачей, помогите!
    #34602383
.gc
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
.gc
Гость
Если для score ограничен диапазон, и распределение более-менее равномерное, то можно ввести масштаб _SCALE_,
таким образом уменьшая этот диапазон на порядки
Код: plaintext
scaled_score = score / _SCALE_
и создать кеш числа пользователей с меньшим (или большим, в зависимости от порядка сортировки) scaled_score
Код: plaintext
1.
2.
3.
create table scaled_score_count (
        scaled_score int unique,
        have_lesser_score int default  0 );
далее в триггерах обновлять его:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
on insert or update on users:
        update scaled_score_count
        set have_lesser_score = have_lesser_score +  1 
        where scaled_score > NEW.score / _SCALE_

on delete or update on users:
        update scaled_score_count
        set have_lesser_score = have_lesser_score -  1 
        where scaled_score > OLD.score / _SCALE_
И вычислять rank в два захода:
Код: plaintext
1.
2.
3.
rank_cache := have_lesser_score from scaled_score_count where scaled_score = user_score / _SCALE_;
rank_more  := count(uid) from users where score >= (user_score/_SCALE_- 1 )*_SCALE_ and score < user_score;
rank_full  := rank_cache + rank_more;
...
Рейтинг: 0 / 0
4 сообщений из 4, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Кто сталкивался с такой задачей, помогите!
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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