Приблизительный план
1
Скрытая сложность повседневной задачи: отображение табличных данных
2
Чем мы занимаемся в КУРСе
3
Все знают, что такое грид
4
Грид – это прокрутка…
5
Грид – это позиционирование…
6
Хороший грид должен
7
��
8
— И разве нет готовых решений?
— А разве это сложно?
и вычитать данные таблицы в массив
9
Подход №1: просто взять
Подход №1: вычитать в массив
10
Проблемы:
11
12
Проблемы:
13
Подход №2: �Переложим задачу на СУБД?
SELECT … WHERE k >= … LIMIT …
Переход к записи по ключу работать будет быстро!
14
Подход №2: �Переложим задачу на СУБД?
Плохие новости:
SELECT COUNT(*) WHERE k<… для определения диапазона полосы прокрутки и позиционирования.
SELECT … OFFSET … LIMIT …
15
Подход №2: �Переложим задачу на СУБД?
16
Проблемы:
17
“The rows skipped by an OFFSET clause still have to be computed inside the server; therefore a large OFFSET might be inefficient.”
— Но чем мы ближе к концу набора, тем больше OFFSET!
– А зачем нам вообще грид со всеми записями?!
18
– А зачем нам вообще грид со всеми записями?!
19
– А зачем нам вообще грид со всеми записями?!
20
Бывает и так:
21
А где полоса прокрутки?
(Обсуждение темы:
https://habrahabr.ru/post/280157/)
— Может, строить «честный грид» �и не надо?
22
— Надо, Федя!
23
Почему нужен «честный» грид?
24
Почему нужен «честный» грид?
25
Почему нужен «честный» грид?
26
27
Как справляются другие ребята?
— С переменным успехом.
28
Наше решение
29
Временное упрощение задачи�(потом ограничения снимем!)
30
CREATE TABLE test (
k INT NOT NULL PRIMARY KEY,
descr VARCHAR(20)
);
Мысленный эксперимент
31
Идея
«Угадаем» взаимосвязь между ключом записи k�и её порядковым номером λ при помощи линейной интерполяции?
32
Насколько хороша линейная интерполяция? (50 из 200)
33
порядковый номер записи
значение ключа
Случай 10 из 200 — похуже…
34
значение ключа
порядковый номер записи
Вероятность наличия �ровно λ записей с ключом <k
35
Теоретическая оценка границ, �мат. ожидания и СКО
36
Неравномерное распределение ключей�— кусочная интерполяция!
37
Снимаем ограничения
— нумеруем возможные комбинации так, чтобы описывались (большим) целым числом
— добавляем сортировочное поле к началу списка ключевых
— нумеруем значения (большими) целыми!
38
39
интерполяционная
таблица
Компоненты алгоритма
нумератор
интер-�полятор
генератор�запросов
Пример
40
Пользователь прокрутил записи…
41
изменилась�позиция бегунка
вычисление
порядкового номера
вычисление
ключа
запрос
ближайшей записи
БД
Нумератор
Интерполятор
Полоса �прокрутки
Интерполяцией находим порядковый номер ключа
42
изменилась�позиция бегунка
вычисление
порядкового номера
вычисление
ключа
запрос
ближайшей записи
БД
Нумератор
Интерполятор
Полоса �прокрутки
Вычисляем примерные значения �полей ключа по примерному номеру
43
изменилась�позиция бегунка
вычисление
порядкового номера
вычисление
ключа
запрос
ближайшей записи
БД
Нумератор
Интерполятор
Полоса �прокрутки
Запрашиваем записи, ближайшие �к найденным примерным значениям полей
44
изменилась�позиция бегунка
вычисление
порядкового номера
вычисление
ключа
запрос
ближайшей записи
БД
Нумератор
Интерполятор
Полоса �прокрутки
name: Мд‘Ukp ®$-'•ДЫ9uj?¦АОZ‡У›:"ZG818*$‰9Ювэ‘
code: я$зec§}0,&-»гФ4%эR
SELECT ... FROM ... WHERE
("name", "code") >= (?, ?) LIMIT ...
Прокрутка в реальном времени
45
Асинхронное уточнение позиции
46
запрос
ближайшей записи
запрос реального�номера записи
SELECT COUNT(*) FROM kladr.street WHERE ("name", "code") < (?, ?)
586038
(А хотели 584600!)
Позиционирование
47
Позиционирование
48
обращение �к таблице по ключу
вычисление
порядкового номера
позиция бегунка
(обр. интерп.)
изменение позиции�бегунка
БД
Нумератор
Интерполятор
Полоса �прокрутки
запрос реального�номера записи
SELECT ... FROM ... WHERE
("name", "code") >= (?, ?) LIMIT ...
SELECT COUNT(*) FROM ...
WHERE ("name", "code") < (?, ?)
Вычисляем порядковый номер ключа
49
обращение �к таблице по ключу
вычисление
порядкового номера
позиция бегунка
(обр. интерп.)
изменение позиции�бегунка
БД
Нумератор
Интерполятор
Полоса �прокрутки
name: Чаадаева
code: 42000010000057000
Интерполяцией находим примерную позицию бегунка
50
обращение �к таблице по ключу
вычисление
порядкового номера
позиция бегунка
(обр. интерп.)
изменение позиции�бегунка
БД
Нумератор
Интерполятор
Полоса �прокрутки
Выставляем бегунок на позицию
51
обращение �к таблице по ключу
вычисление
порядкового номера
позиция бегунка
(обр. интерп.)
изменение позиции�бегунка
БД
Нумератор
Интерполятор
Полоса �прокрутки
запрос реального�номера записи
Осталось разобраться в одном вопросе…
Как работает нумератор?
52
Функция нумератора
53
54
Составной ключ/сортировка:�ORDER BY X, Y
55
Составной ключ
Если умеем работать �с парами значений —
�
56
Составной ключ
Если умеем работать �с парами значений —
�— то можем работать �и с произвольными N-ками значений
57
Как отыскивать записи �от составного ключа?
(работает только в PostgreSQL)
не использует индекс!
58
Нумерация строк
59
Интерполяция строк
60
61
Пустая строка, строка из одной буквы, из двух букв…
62
‘’ — 0, ‘а’ — 1, ‘б’ — ?
2 — неправильный ответ: ‘абак’, ‘араб’, ‘арка’…
63
64
Ничего не упустили?.. �Пишем тест:
ИЖЕВСК 297544850130486
ИРКУТСК 309090873152681
ЙОШКАР-ОЛА 343626219328684
Реальность: �SELECT name FROM city ORDER BY name�(PostgreSQL с настройками по умолчанию)
66
Правила сортировки (collation rules)
Результат «подгонки» правил к PostgreSQL:
…<в,В<г,Г<д,Д<е,Е;ё,Ё<ж,Ж<з,З<и,И;й,Й<к,К<л,Л…�
67
java.text.RuleBasedCollator extends java.text.Collator
java.text.CollationKey
Строка с точки зрения Collation Rule
68
Й | о | ш | к | а | р | - | О | л | а |
64 | 69 | 73 | 65 | 5C | 6B | 01 | 69 | 66 | 5C |
01 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
01 | 00 | 00 | 00 | 00 | 00 | 00 | 01 | 00 | 00 |
Насколько всё это быстро?
JMH-замер:
69
Первоначальное заполнение интерполяционной таблицы
70
А также не упомянуты…
…и другие мелкие, но важные детали
“God is in the detail.”
71
Выводы
1. Создавать фреймворк — дело трудное�и неблагодарное
72
Выводы
2. Всегда помните�про О-оценку сложности алгоритмов
73
Выводы
3. По возможности, избегайте COUNT �и OFFSET
74
Выводы
75
Ссылки
76
Вопросы?
77