Как сериализация таблицы с внешним ключом работает внутри KDB - PullRequest
0 голосов
/ 13 апреля 2020

У меня есть таблица ключей (ссылочная таблица), связанная внешним ключом с ссылочной таблицей, и я сериализую обе таблицы с помощью оператора set.

q)kt:([sym:`GOOG`AMZN`FB]; px:20 30 40);
q)`:/Users/uts/db/kt set kt
q)t:([] sym:`kt$5?`GOOG`AMZN`FB; vol:5?10000)
q)`:/Users/uts/db/t set t

Затем я удаляю эти таблицы из памяти

q)delete kt,t from `.

Теперь я десериализирую таблицу t в памяти:

t:get `:/Users/uts/db/t

Если после этого я выполню meta t, она потерпит неудачу, ожидая, что kt будет внешним ключом. Если я печатаю t, как и ожидалось, он показывает значения индекса в столбце sym таблицы t.

Итак, возникает вопрос -

  1. Поскольку kdb хранит мета каждой таблицы (т. е. c, t, f, a) и соответствующие значения на диске, как внутренне работает сериализация таблицы t?

  2. Как (в какой форме в двоичном формате) они значения хранятся в файле т.

    -rw-r--r-- 1 uts staff 100 Apr 13 23:09 t

1 Ответ

2 голосов
/ 14 апреля 2020

tl; dr Внешний ключ сохраняется как вектор 4-байтовых индексов ключевого столбца ссылочной таблицы плюс имя таблицы, к которой относится внешний ключ.

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

Позвольте мне немного изменить ваш пример, чтобы сделать вещи проще .

q)show kt:([sym:`GOOG`AMZN`FB]; px:20 30 40)
sym | px
----| --
GOOG| 20
AMZN| 30
FB  | 40
q)show t:([] sym:`kt$`GOOG`GOOG`AMZN`FB`FB)
sym
----
GOOG
GOOG
AMZN
FB
FB

Я оставил только один столбец - sym - в t, поскольку vol не имеет отношения к вопросу. Давайте сначала сохраним t без каких-либо данных :

q)`:/tmp/t set 0#t
`:/tmp/t
q)hcount `:/tmp/t
30

Теперь мы знаем, что для представления t, когда он пуст, требуется 30 байтов. Давайте посмотрим, есть ли шаблон, когда мы начинаем добавлять строки к t:

q){`:/tmp/t set x#t;`cnt`size!(x;hcount[`:/tmp/t] - 30)} each til[11], 100 1000 1000000
cnt     size
---------------
0       0
1       4
2       8
3       12
4       16
5       20
6       24
7       28
8       32
9       36
10      40
100     400
1000    4000
1000000 4000000

Мы можем видеть, что добавление одной строки увеличивает размер t на четыре байта. Что могут быть эти 4 байта? Могут ли они представлять собой символ? Нет, потому что, если бы они были, и мы переименовали значение sym в kt, это затронуло бы размер t на диске, но не:

q)update sym:`$50#.Q.a from `kt where sym=`GOOG
`kt
q)1#t
sym
--------------------------------------------------
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx
q)`:/tmp/t set 1#t
`:/tmp/t
q)hcount `:/tmp/t
34

Все еще 34 байта. Я думаю, к настоящему времени должно быть очевидно, что 4 байта - это индекс, но индекс чего? Это индекс столбца, который должен называться sym точно? Очевидно нет, это не так.

q)kt:`foo xcol kt
q)t
sym
--------------------------------------------------
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx
AMZN
FB
FB

Нет столбца с именем sym в kt, но t вообще не изменился! Мы можем go еще дальше и изменить тип foo (ex sym) в kt:

q)update foo:-1 -2 -3.0 from `kt
`kt
q)t
sym
---
-1
-1
-2
-3
-3

Мало того, что он изменил t, но и его мета:

q)meta t
c  | t f  a
---| ------
sym| f kt
q)/  ^------- used to be s

Надеюсь, теперь ясно, что kdb хранит 4-байтовый индекс ключевого столбца ссылочной таблицы и имя таблицы (но не имя ключевого столбца!). Если ссылка на таблицу отсутствует, kdb не может восстановить исходные данные и отображает оголенный индекс. Если ссылочную таблицу необходимо отправить по проводам, то индексы заменяются фактическими значениями, чтобы принимающая сторона могла видеть реальные данные.

...