После MySQL 5.7.8 json изначально поддерживается. В базе данных nosql, такой как mongodb, для хранения данных очень естественно использовать json. Разумное использование json в mysql может принести большое удобство.
Сценарии использования полей Json
Читая примеры руководств по laravel, мы часто видим$user->is_adminЧтобы определить является ли пользователь администратором, но в таблице пользователей admin обычно занимает лишь малую часть.Очень ненужно открывать поле is_admin.В БД будет много бессмысленного хранилища данных,мы можем его использовать для пользователя Таблица создает поле json для хранения нашего поля is_admin
[
{
id: 1,
username: 'weiwenhao',
rest: { // 冗余字段
is_admin: 1
}
},
{
id: 2,
username: 'eienao',
rest: null
}
]
Конечно, даже если мы не используем json, мы не будем использовать is_admin, чтобы судить, является ли он администратором.
Администратора можно отметить, добавив таблицу администратора или RABC.
Это по-прежнему таблица пользователей.Очень распространенное требование — сторонний вход в систему.Если мы добавим его непосредственно в таблицу пользователей.facebook_id,facebook_email,facebook_phone_number,google_id,....поля, которые могут привести к большому количеству бессмысленных данных (даже если они не занимают память или не влияют на производительность)
Одним из решений является использование отношения «один ко многим», которое заключается в создании сторонней таблицы входа в систему для хранения идентификатора/электронной почты/номера телефона стороннего входа в систему и т. д.
Но я предпочитаю использовать поля json для решения этой проблемы.
[
{
id: 1,
username: 'weiwenhao',
rest: {
is_admin: 1,
facebook_id: 2348234,
facebook_phone_number: 2834723234,
}
},
{
id: 2,
username: 'eienao',
rest: {
google_id: 2348234,
google_email: xxx@gmail.com
}
}
]
Видно, что использование полей json делает оформление таблицы данных более естественным и централизованным, а бизнес соответственно проще и удобнее.
Использование полей Json в laravel
Во-первых, это файл миграции$table->json('rest')->nullable();
Laravel в определенной степени оптимизировал использование json, для обновления и создания мы можем.
$user = new User;
$user->{'rest->google_id'} = 'xxx';
# 如果你的rest字段为null,那么上面的操作会使 null 会变成 {google_id: "xxx"}, 不需要再做 是否为null的判定啦
# 如果仅使用上面的插入操作,也不需要在使用模型的修改器来吧 json => array, array => json啦
Когда значение поля rest равно null, пакетная операция не может быть выполнена, подобно
update(['rest->google_id' => 'xxx'])Такая операция недействительна, поэтому вышеописанный метод более рекомендуется для выполнения операции обновления.
Удобно использовать для поисковой операции
User::where('rest->google_id','xxx')->firstOrFail()
Что касается эффективности поиска, решение дается в следующем содержании.
Сгенерированный столбец
5.7 Добавлен сгенерированный столбец.Значение сгенерированного столбца вычисляется в соответствии с выражением, содержащимся в определении столбца.Официальный пример: вычислить длину гипотенузы прямоугольного треугольника.
CREATE TABLE triangle (
sidea DOUBLE,
sideb DOUBLE,
sidec DOUBLE AS (SQRT(sidea * sidea + sideb * sideb)) # AS (expression) 为生成列的核心语法
);
INSERT INTO triangle (sidea, sideb) VALUES(1,1),(3,4),(6,8);
# 对于上面的插入,查询可以得到如下结果
mysql> SELECT * FROM triangle;
+-------+-------+--------------------+
| sidea | sideb | sidec |
+-------+-------+--------------------+
| 1 | 1 | 1.4142135623730951 |
| 3 | 4 | 5 |
| 6 | 8 | 10 |
+-------+-------+--------------------+
Значение sidec выше рассчитывается на основе sidea и sideb и фактически не сохраняется на диске.До mysql5.7 мы могли написать операторы sql, подобные этому, для достижения вышеуказанных требований.
SELECT *,(SQRT(sidea * sidea + sideb * sideb)) as sidec FROM triangle;
Выше приведена основная функция генерируемого столбца.На самом деле генерируемый столбец имеет два подтипа.Приведенный выше пример относится к виртуальному (виртуальному) типу генерируемого столбца, который фактически не хранит значение сайдека на диске.
В дополнение к виртуальному сгенерированный столбец также поддерживает хранимый тип, а оператор его создания
#...
sidec DOUBLE AS (SQRT(sidea * sidea + sideb * sideb)) STORED # stored不指定则默认为 virtual
#...
Когда строка создается или обновляется, sidec пересчитывается и сохраняется на диске.
Еще одной важной особенностью сгенерированных столбцов является то, что их можноГенерирует результат оценки выражения столбца для построения индекса, Способ индексации такой же, как и для обычных полей.1
CREATE TABLE triangle (
sidea DOUBLE,
sideb DOUBLE,
sidec DOUBLE AS (SQRT(sidea * sidea + sideb * sideb)) # AS (expression) 为生成列的核心语法
INDEX(`sidec`)
);
Сам индекс также является реальным веществом, хранящимся на диске, поэтому виртуальный генерирует столбец + индекс, что позволяет добиться наиболее эффективного использования дискового пространства.
Для сохраненного сгенерированного столбца + индекс обычно не осуществляется доступ к сохраненному сгенерированному столбцу, хранящемуся на диске, но доступ к индексу осуществляется напрямую, поэтому нет необходимости использовать сохраненный сгенерированный столбец.
Добавить индекс в поле в json, используя сгенерированный столбец
Возьмите в качестве примера rest.google_id пользовательской таблицы, создайте таблицу
#...
`rest` json NULL,
# JSON_EXTRACT(`rest`,'$.google_id') 等价于 `rest`->'$.google_id'
# 5.7.13版本后
# JSON_UNQUOTE(JSON_EXTRACT(`rest`,'$.google_id')) 等价于 `rest`->>'$.google_id'
# 使用生成列为json添加索引时,请务必使用 JSON_UNQUOTE(JSON_EXTRACT(`rest`,'$.google_id'))/->>
`google_id` varchar GENERATED ALWAYS AS (`rest`->>'$.google_id')) NULL
UNIQUE INDEX(`google_id`)
#...
в файле миграции laravel
$table->json('rest')->nullable();
$table->string('rest')->nullable()->unique()->virtualAs('`oauth`->>"$.google_id"');
С индексом, когда мы выполняем операцию запроса
select * from users where `rest`->'$.google_id' = 'xxx' # 通常使用这种更加简单的形式
select * from users where `rest`->>'$.google_id' = 'xxx'
# 上面两种表达式会被mysql的优化器在查询阶段自动优化为 select * from users where google_id = 'xxx'
некоторые дополнения
-
virtualAs(oauth->"$.google_id"');Использование символа **->** для создания сгенерированного столбца приведет к тому, что индекс не будет использоваться.Причина не очень ясна.Нужно продолжить изучение руководства.Кроме того, для оператора созданияGENERATED ALWAYSэффект не очень ясен. -
Что касается null, часто можно увидеть, что использование null в качестве значения поля по умолчанию в mysql приведет к сбою индекса. Но после запроса я обнаружил, что это старая теория китайской медицины. Я предпочитаю использовать null как значение по умолчанию, вместо ''/0/0.0, я думаю, что null более выразительно, и laravel всегда представляет эту идею.
-
Что касается использования json, то в последних проектах в большинстве моих основных таблиц есть поле json для хранения и избыточности некоторых неосновных данных.