Первичные и вторичные индексы Paradox§
Исследованы индексы DB/1_sem_2026_2027 чтением заголовков и активных цепочек блоков. Исходные файлы не изменялись. Скрипт research/inspect_indexes.py отдельно разбирает вторичные индексы типа 8, а текущие таблицы читает через существующий tools/paradox_read.py без его изменения. Результаты и контрольные суммы сохранены в research/indexes-evidence.json.
1. Парность первичных индексов§
Имена сопоставлены без учета регистра, как в типичном Windows-окружении исходного приложения. Получено 18 пар:
| Таблица | Первичный индекс |
|---|---|
CHAIRS.DB |
CHAIRS.PX |
Classes.DB |
Classes.PX |
CLASSINF.DB |
CLASSINF.PX |
Courses.DB |
Courses.PX |
DAYS.DB |
DAYS.PX |
FACULTY.DB |
FACULTY.PX |
GROUPS.DB |
GROUPS.PX |
GRPPLAN.DB |
GRPPLAN.PX |
Plan.DB |
Plan.PX |
PLANITEM.DB |
PLANITEM.PX |
PLANROOM.DB |
PLANROOM.PX |
ROOMRSTR.DB |
ROOMRSTR.PX |
Rooms.DB |
Rooms.PX |
STREAMS.DB |
STREAMS.PX |
SUBJECTS.DB |
SUBJECTS.PX |
TCHRRSTR.DB |
TCHRRSTR.PX |
TEACHERS.DB |
TEACHERS.PX |
TIMES.DB |
TIMES.PX |
Исключения: ClassesInf.DB без ClassesInf.PX и LOAD.PX без LOAD.DB. ClassesInf.DB не объявляет первичный ключ, поэтому такая структура допустима. LOAD.PX — оставшийся файл исторического семейства; наличие LOAD.TV и LOAD.FAM со ссылками на CLASSES подтверждает исторические следы, но не доказывает утрату LOAD.DB. Сами .PX — индексы Paradox, не изображения.
2. Все шесть вторичных индексов§
В каждой паре .XG* — упорядоченный набор индексных значений, а .YG* — связанная с ним индексная структура. Заголовки .XG* содержат fileType = 8, versionID = 11 (семейство формата Paradox 5), кодовую страницу 866, блоки по 2 048 байт, заголовок 2 048 байт. У .YG* установлен fileType = 7; структура заголовка отличается, поэтому чтение кодовой страницы по смещению обычного .DB для .YG* ошибочно. Основа разбора — исходный код pxlib, get_px_head(), с проверкой на фактических файлах.
| Файлы | Внутреннее имя индекса | Поля индекса в порядке | Первичный ключ исходной таблицы | Записей |
|---|---|---|---|---|
Classes.XG0 + Classes.YG0 |
PlanNoIdx |
PlanNo |
ClassNo |
15 111 |
Classes.XG1 + Classes.YG1 |
TeacherNoIdx |
TeacherNo |
ClassNo |
15 111 |
GROUPS.XG0 + GROUPS.YG0 |
GroupStreamIdx |
StreamNo |
GroupNo |
554 |
GRPPLAN.XG0 + GRPPLAN.YG0 |
PlanGroupIdx |
PlanNo, GroupNo, Subgroup |
GroupNo, Subgroup, PlanNo |
21 419 |
STREAMS.XG0 + STREAMS.YG0 |
StreamNameIdx |
StreamName |
StreamNo |
140 |
TEACHERS.XG0 + TEACHERS.YG0 |
TeacherFacultyIdx |
ChairNo |
TeacherNo |
866 |
Обратить внимание: имя TeacherFacultyIdx содержит слово Faculty, но фактическое поле индекса — ChairNo, то есть кафедра. Название индекса не следует превращать в недоказанную связь преподавателя непосредственно с факультетом.
3. Для чего эти индексы нужны в приложении§
PlanNoIdxускоряет получение занятий по записи учебной нагрузки/плана.TeacherNoIdxускоряет отбор занятий конкретного преподавателя.GroupStreamIdxпомогает получать группы, включенные в поток.PlanGroupIdxпозволяет переходить от записи плана к связанным группам и подгруппам. Этот порядок начинается сPlanNo, в отличие от первичного ключаGRPPLAN, который начинается сGroupNo.StreamNameIdxобеспечивает поиск/сортировку потоков по названию.TeacherFacultyIdxпо содержимому позволяет выбирать преподавателей кафедры.
Это выводы из состава ключей. Наличие индекса показывает предусмотренный путь быстрого доступа, но не доказывает, что конкретная кнопка интерфейса всегда использует именно его.
4. Как установлены поля и как выполнена проверка§
В .XG* содержательные поля вторичного ключа предшествуют полям первичного ключа исходной таблицы. Завершающее служебное поле имеет имя Blk Num и тип Short. Например, полный набор Classes.XG0: PlanNo, ClassNo, Blk Num. Для GRPPLAN.XG0 полный набор: PlanNo, GroupNo, Subgroup, GroupNo, Subgroup, PlanNo, Blk Num. Повторяющиеся имена здесь ожидаемы; запрет повторяющихся полей из обычного .DB-парсера к нему неприменим.
Имена полей всех индексов, кроме GRPPLAN.XG0, начинаются со смещения 0xDD; у GRPPLAN.XG0 — с 0xF5. После имен расположены номера полей, идентификатор сортировки cyrr и имя индекса. Полные смещения и размеры каждого поля находятся в JSON-доказательствах.
Прочитаны все записи всех шести .XG* по активным цепочкам блоков. Проверены размеры записей, предыдущие/следующие блоки, отсутствие циклов и совпадение числа записей с заголовком. Для каждого индекса мультимножество «вторичный ключ + первичный ключ» сравнено с соответствующей .DB: все шесть совпали. Это более строгая проверка, чем одно сравнение количества строк.
У STREAMS.XG0 текстовые ключи хранятся прописными буквами, тогда как STREAMS.DB сохраняет исходный регистр. Все 140 ключей совпали после приведения регистра. Это согласуется с нормализацией для поиска без учета регистра. При построении веб-каталога отображаемое название нужно брать из .DB, а не из индекса. Для остальных пяти индексов числовые значения совпали без нормализации.
Дополнительная диагностика Blk Num§
Числовое поле Blk Num дополнительно сравнили с фактическим номером блока, в котором сейчас находится строка с тем же первичным ключом в .DB. Получились расхождения:
| Индекс | Расхождений Blk Num с текущим блоком таблицы |
|---|---|
Classes.XG0 |
1 765 |
Classes.XG1 |
370 |
GROUPS.XG0 |
14 |
GRPPLAN.XG0 |
1 126 |
STREAMS.XG0 |
140 |
TEACHERS.XG0 |
406 |
Это диагностическое наблюдение, не заключение о повреждении индексов. Значения ключей полностью согласованы, а точная актуальность/обновление служебной подсказки Blk Num в используемой версии BDE здесь не проверены. Нельзя на основании этого поля автоматически исправлять или перестраивать исходники. Новый просмотрщик может надежно извлекать записи из самих .DB по их активной цепочке блоков; для проверки старого индексного поиска нужно отдельно открыть рабочую копию в оригинальном окружении. Индексное дерево .YG* целиком не проверялось.
5. Практический вывод для веб-слоя§
Извлеченные вторичные ключи дают готовую основу индексов SQLite/PostgreSQL: Classes(PlanNo), Classes(TeacherNo), Groups(StreamNo), GrpPlan(PlanNo, GroupNo, Subgroup), Streams(StreamName) с продуманной русской сортировкой, Teachers(ChairNo). Это рекомендации для новой базы, а не изменения старых файлов.
Служебные .XG/.YG/.PX полезны для описания архитектуры и независимой проверки выгрузки, но веб-интерфейс не должен выдавать их за отдельные предметные таблицы или копировать служебный Blk Num в бизнес-модель расписания.