Генерируемые столбцы
Начиная с версии 3.1, Selena поддерживает генерируемые столбцы. Генерируемые столбцы можно использовать для ускорения запросов со сложными выражениями. Эта функция поддерживает предварительное вычисление и сохранение результатов выражений и перезапись запросов, что значительно ускоряет запросы с теми же сложными выражениями.
Вы можете определить один или несколько генерируемых столбцов для хранения результатов выражений при создании таблицы. Таким образом, при выполнении запросов, содержащих выражение, результаты которого хранятся в определённом вами генерируемом столбце, CBO перезаписывает запрос для чтения данных непосредственно из генерируемого столбца. Также вы можете напрямую запрашивать данные из генерируемого столбца.
Также рекомендуется оценить влияние генерируемых столбцов на производительность загрузки, поскольку вычисление выражений занимает некоторое время. Кроме того, рекомендуется создавать генерируемые столбцы при создании таблицы вместо добавления или изменения их после создания таблицы. Это связано с тем, что до бавление или изменение генерируемых столбцов после создания таблицы требует много времени и ресурсов.
Однако обратите внимание, что при загрузке данных в таблицы с генерируемым столбцом время и накладные расходы могут увеличиться, поскольку Selena необходимо выполнить дополнительные вычисления для расчёта результатов на основе выражения и записать результаты в генерируемый столбец.
Начиная с версии 3.5.0, cluster Selena с разделяемыми данными поддерживают генерируемые столбцы.
Базовые операции
Создание генерируемых столбцов
Синтаксис
<col_name> <data_type> [NULL] AS <expr> [COMMENT 'string']
Создание генерируемых столбцов при создании таблицы
Создайте таблицу с именем test_tbl1 с пятью столбцами, из которых столбцы newcol1 и newcol2 являются генерируемыми столбцами, значения которых вычисляются с использованием указанных выражений и ссылаются на значения обычных столбцов data_array и data_json соответственно.
CREATE TABLE test_tbl1
(
id INT NOT NULL,
data_array ARRAY<int> NOT NULL,
data_json JSON NOT NULL,
newcol1 DOUBLE AS array_avg(data_array),
newcol2 String AS json_string(json_query(data_json, "$.a"))
)
PRIMARY KEY (id)
DISTRIBUTED BY HASH(id);
ПРИМЕЧАНИЕ:
- Генерируемые столбцы должны быть определены после обычных столбцов.
- Агрегатные функции не могут использоваться в выражениях для генерируемых столбцов.
- Выражения для генерируемых столбцов не могут ссылаться на другие генерируемые столбцы или столбцы с автои нкрементом, но выражения могут ссылаться на несколько обычных столбцов.
- Тип данных генерируемого столбца должен соответствовать типу данных результата, генерируемого выражением для генерируемого столбца.
- Генерируемые столбцы не могут быть созданы для таблиц Aggregate.
Добавление генерируемых столбцов после создания таблицы
В большинстве случаев часто и спользуемые при запросах выражения определяются после создания таблицы, поэтому генерируемые столбцы часто добавляются после создания таблицы. Для повышения производительности внутренняя логика Selena для добавления генерируемых столбцов после создания таблицы оптимизирована. Таким образом, при добавлении генерируемого столбца Selena не нужно перезаписывать все данные. Вместо этого Selena нужно только записать данные нового генерируемого столбца и связать эти данные с существующими физическими файлами данных, что значительно повышает эффективность добавления генерируемых столбцов после создания таблицы.
-
Создайте таблицу с именем
test_tbl2с тремя обычными столбцамиid,data_arrayиdata_json. Вставьте строку данных в таблицу.-- Создание таблицы.
CREATE TABLE test_tbl2
(
id INT NOT NULL,
data_array ARRAY<int> NOT NULL,
data_json JSON NOT NULL
)
PRIMARY KEY (id)
DISTRIBUTED BY HASH(id);
-- Вставка строки данных.
INSERT INTO test_tbl2 VALUES (1, [1,2], parse_json('{"a" : 1, "b" : 2}'));
-- Запрос к таблице.
MySQL [example_db]> select * from test_tbl2;
+------+------------+------------------+
| id | data_array | data_json |
+------+------------+------------------+
| 1 | [1,2] | {"a": 1, "b": 2} |
+------+------------+------------------+
1 row in set (0.04 sec) -
Выполните ALTER TABLE ... ADD COLUMN ... для добавления генерируемых столбцов
newcol1иnewcol2, которые создаются путём вычисления выражений на основе значений обычных столбцовdata_arrayиdata_json.ALTER TABLE test_tbl2
ADD COLUMN newcol1 DOUBLE AS array_avg(data_array);
ALTER TABLE test_tbl2
ADD COLUMN newcol2 String AS json_string(json_query(data_json, "$.a"));ПРИМЕЧАНИЕ:
- Добавление генерируемых столбцов в таблицы Aggregate не поддерживается.
- Обычные столбцы должны быть определены перед генерируемыми столбцами. При использовании оператора ALTER TABLE ... ADD COLUMN ... для добавления обычного столбца без указания его позиции система автоматически размещает его перед генерируемыми столбцами. Кроме того, нельзя использовать AFTER для явного размещения обычного столбца после генерируемого столбца.
-
Запрос данных таблицы.
MySQL [example_db]> SELECT * FROM test_tbl2;
+------+------------+------------------+---------+---------+
| id | data_array | data_json | newcol1 | newcol2 |
+------+------------+------------------+---------+---------+
| 1 | [1,2] | {"a": 1, "b": 2} | 1.5 | 1 |
+------+------------+------------------+---------+---------+
1 row in set (0.04 sec)Результат показывает, что генерируемые столбцы
newcol1иnewcol2добавлены в таблицу, и Selena автоматически вычислила их значения на основе выражения.
Загрузка данных в генерируемые столбцы
Во время загрузки данных Selena автоматически вычисляет значения для генерируемых столбцов на основе выражений. Вы не можете указать значения генерируемых столбцов. В следующем примере используется оператор INSERT INTO для загрузки данных:
-
Используйте INSERT INTO для вставки записи в таблицу
test_tbl1. Обратите внимание, что нельзя указывать значения для генерируемых столбцов в предложенииVALUES ().INSERT INTO test_tbl1 (id, data_array, data_json)
VALUES (1, [1,2], parse_json('{"a" : 1, "b" : 2}')); -
Запрос данных таблицы.
MySQL [example_db]> SELECT * FROM test_tbl1;
+------+------------+------------------+---------+---------+
| id | data_array | data_json | newcol1 | newcol2 |
+------+------------+------------------+---------+---------+
| 1 | [1,2] | {"a": 1, "b": 2} | 1.5 | 1 |
+------+------------+------------------+---------+---------+
1 row in set (0.01 sec)Результаты показывают, что Selena автоматически вычислила значения для генерируемых столбцов
newcol1иnewcol2на основе выражений.ПРИМЕЧАНИЕ:
Следующая ошибка возвращается, если вы указываете значения для генерируемых столбцов во время загрузки данных:
MySQL [example_db]> INSERT INTO test_tbl1 (id, data_array, data_json, newcol1, newcol2)
VALUES (2, [3,4], parse_json('{"a" : 3, "b" : 4}'), 3.5, "3");
ERROR 1064 (HY000): Getting analyzing error. Detail message: materialized column 'newcol1' can not be specified.
MySQL [example_db]> INSERT INTO test_tbl1 VALUES (2, [3,4], parse_json('{"a" : 3, "b" : 4}'), 3.5, "3");
ERROR 1064 (HY000): Getting analyzing error. Detail message: Column count doesn't match value count.
Изменение генерируемых столбцов
При изменении генерируемого столбца Selena необходимо перезаписать все данные, что требует много времени и ресурсов. Если использование ALTER TABLE для изменения генерируемых столбцов неизбежно, рекомендуется заранее оценить затраты и время.
Вы можете изменить тип данных и выражение генерируемого столбца.
-
Создайте таблицу
test_tbl3с пятью столбцами, из которых столбцыnewcol1иnewcol2являются генерируемыми столбцами, значения которых вычисляются с использованием указанных выражений и ссылаются на значения обычных столбцовdata_arrayиdata_jsonсоответственно. Вставьте строку данных в таблицу.-- Создание таблицы.
MySQL [example_db]> CREATE TABLE test_tbl3
(
id INT NOT NULL,
data_array ARRAY<int> NOT NULL,
data_json JSON NOT NULL,
-- Типы данных и выражения генерируемых столбцов указаны следующим образом:
newcol1 DOUBLE AS array_avg(data_array),
newcol2 String AS json_string(json_query(data_json, "$.a"))
)
PRIMARY KEY (id)
DISTRIBUTED BY HASH(id);
-- Вставка строки данных.
INSERT INTO test_tbl3 (id, data_array, data_json)
VALUES (1, [1,2], parse_json('{"a" : 1, "b" : 2}'));
-- Запрос к таблице.
MySQL [example_db]> select * from test_tbl3;
+------+------------+------------------+---------+---------+
| id | data_array | data_json | newcol1 | newcol2 |
+------+------------+------------------+---------+---------+
| 1 | [1,2] | {"a": 1, "b": 2} | 1.5 | 1 |
+------+------------+------------------+---------+---------+
1 row in set (0.01 sec) -
Изменение генерируемых столбцов
newcol1иnewcol2:-
Изменение типа данных генерируемого столбца
newcol1наARRAY<INT>и изменение его выражения наdata_array.ALTER TABLE test_tbl3
MODIFY COLUMN newcol1 ARRAY<INT> AS data_array; -
Изменение выражения генерируемого столбца
newcol2для извлечения значений поляbиз обычного столбцаdata_json.ALTER TABLE test_tbl3
MODIFY COLUMN newcol2 String AS json_string(json_query(data_json, "$.b"));
-
-
Просмотр изменённой схемы и данных в таблице.
-
Просмотр изменённой схемы.
MySQL [example_db]> show create table test_tbl3\G
**** 1. row ****
Table: test_tbl3
Create Table: CREATE TABLE test_tbl3 (
id int(11) NOT NULL COMMENT "",
data_array array<int(11)> NOT NULL COMMENT "",
data_json json NOT NULL COMMENT "",
-- После изменения типы данных и выражения генерируемых столбцов следующие:
newcol1 array<int(11)> NULL AS example_db.test_tbl3.data_array COMMENT "",
newcol2 varchar(65533) NULL AS json_string(json_query(example_db.test_tbl3.data_json, '$.b')) COMMENT ""
) ENGINE=OLAP
PRIMARY KEY(id)
DISTRIBUTED BY HASH(id)
PROPERTIES (...);
1 row in set (0.00 sec) -
Запрос данных таблицы после изменения. Результат показывает, что Selena пересчитала значения генерируемых столбцов
newcol1иnewcol2на основе изменённых выражений.MySQL [example_db]> select * from test_tbl3;
+------+------------+------------------+---------+---------+
| id | data_array | data_json | newcol1 | newcol2 |
+------+------------+------------------+---------+---------+
| 1 | [1,2] | {"a": 1, "b": 2} | [1,2] | 2 |
+------+------------+------------------+---------+---------+
1 row in set (0.01 sec)
-
Удаление генерируемого столбца
Удаление столбца newcol1 из таблицы test_tbl3
ALTER TABLE test_tbl3 DROP COLUMN newcol1;
ПРИМЕЧАНИЕ:
Если генерируемый столбец ссылается на обычный столбец в выражении, вы не можете напрямую удалить или изменить этот обычный столбец. Вместо этого вам нужно сначала удалить генерируемый столбец, а затем удалить или изменить обычный столбец.
Перезапись запросов
Если выражение в запросе совпадает с выражением генерируемого столбца, оптимизатор автоматически перезаписывает запрос для прямого чтения значений генерируемого столбца.
-
Предположим, что вы создаёте таблицу
test_tbl4со следующей схемой:CREATE TABLE test_tbl4
(
id INT NOT NULL,
data_array ARRAY<int> NOT NULL,
data_json JSON NOT NULL,
newcol1 DOUBLE AS array_avg(data_array),
newcol2 String AS json_string(json_query(data_json, "$.a"))
)
PRIMARY KEY (id) DISTRIBUTED BY HASH(id); -
Если вы запрашиваете данные в таблице
test_tbl4с помощью оператораSELECT array_avg(data_array), json_string(json_query(data_json, "$.a")) FROM test_tbl4;, запрос включает только обычные столбцыdata_arrayиdata_json. Однако выражения в запросе совпадают с выражениями генерируемых столбцовnewcol1иnewcol2. В этом случае план выполнения показывает, что CBO автоматически перезаписывает запрос для чтения значений генерируемых столбцовnewcol1иnewcol2.MySQL [example_db]> EXPLAIN SELECT array_avg(data_array), json_string(json_query(data_json, "$.a")) FROM test_tbl4;
+---------------------------------------+
| Explain String |
+---------------------------------------+
| PLAN FRAGMENT 0 |
| OUTPUT EXPRS:4: newcol1 | 5: newcol2 | -- Запрос перезаписан для чтения данных из генерируемых столбцов newcol1 и newcol2.
| PARTITION: RANDOM |
| |
| RESULT SINK |
| |
| 0:OlapScanNode |
| TABLE: test_tbl4 |
| PREAGGREGATION: ON |
| partitions=0/1 |
| rollup: test_tbl4 |
| tabletRatio=0/0 |
| tabletList= |
| cardinality=1 |
| avgRowSize=2.0 |
+---------------------------------------+
15 rows in set (0.00 sec)