How*_*ame 10 postgresql database-design
我正在设计一个模式来支持用户活动的日志记录,用户必须能够搜索:
我创建了这个架构:
并设计查询以进行搜索:
在所有事件中:
SELECT extract(epoch from log_time) * 1000,
u.username,
CASE WHEN l.event_type IN (0, 2) THEN e.template
WHEN l.event_type = 1 THEN format(e.template, ecs.field)
WHEN l.event_type = 3 THEN format(e.template, ess.field)
WHEN l.event_type = 4 THEN format(e.template, ect.ip, ect.port)
END
FROM logs l
JOIN users u ON u.id = l.user_id
JOIN event_def e ON e.id = l.event_type
LEFT JOIN event_client_search ecs ON ecs.log_id = l.id
LEFT JOIN event_switch_search ess ON ess.log_id = l.id
LEFT JOIN event_cable_test ect ON ect.log_id = l.id
Run Code Online (Sandbox Code Playgroud)跨同类型事件:
SELECT extract(epoch from log_time) * 1000,
u.username,
format(e.template, ect.ip, ect.port)
FROM logs l
JOIN users u ON u.id = l.user_id
JOIN event_def e ON e.id = l.event_type
JOIN event_cable_test ect ON ect.log_id = l.id
Run Code Online (Sandbox Code Playgroud)这是event_def表的样子:
id | template
----+----------------------------------------
0 | Logged in
2 | Logged out
1 | Searched in clients %s
3 | Searched in switches %s
4 | Cable test switch %s port %s
Run Code Online (Sandbox Code Playgroud)
但是我不喜欢的是,当我有大约 100 个事件(现在我有大约 50 个,但还没有实现它们)时,这将是一个性能问题。
所以我想合并具有相同参数的事件,如下所示:
我认为这不会有太大帮助(它最多可以将事件数量减少一半),也许我在思考错误的方向?
我要求您重新考虑的假设之一是您是否真的希望为每种事件类型使用不同的表,或者这些事件类型是否是表中的行而不是不同的表。
如果您有一个EVENT_TYPE
包含事件类型列表(大约 100 个)的表,您可以从当前的各种事件表中获取列,并将它们排在EVENT_PARAMETER
表中。
当您添加新的事件类型时,这种类型的设计会将您的架构更改转换为数据更改。这将节省您的代码维护问题,并避免使您的查询更复杂和可能更慢。
事件的实例将类似地保存在两个表中,例如一个LOG
表和一个LOG_DETAIL
表。
LOG
将是用户和事件类型之间的交集。
LOG_DETAIL
将是日志和事件参数之间的交集。
您的数据模型可能如下所示:
请注意,有些人可能对这种方法有一个反对意见,即您最终将日志参数值保存为字符串格式,而不是本机格式。这显然是一种权衡。您必须问问自己,这是否适合您的情况。
小智 1
如果您愿意接受非关系方法,您最终可能会得到一个更干净的模式:
table event_log
id | occurred_at | event_type | attributes
1 | 2016-01-01 00:00:00 | user.registered | {"user.id": 1, "user.role": "admin"}}
2 | 2016-01-01 00:01:00 | user.exploded | {"user.id": 1}
table attribute_search_index
event_id | attribute_name | attribute_value
1 | user.id | 1
1 | user.role | admin
2 | user.id | 1
table event_format (optional)
event_type | format
user.registered | User {user.id} has registered with role {user.role}
user.exploded | User {user.id} has exploded
Run Code Online (Sandbox Code Playgroud)
这种模式将允许您搜索事件,但每个参数需要一个额外的连接:
SELECT e.* FROM event_log AS e
INNER JOIN attribute_search_index AS p1
ON p1.event_id = e.id
AND p1.attribute_name = 'user.id'
AND p1.attribute_value = '1'
INNER JOIN attribute_search_index AS p2
ON p2.event_id = e.id
AND p2.attribute_name = 'user.role'
AND p2.attribute_value = 'admin'
WHERE e.type = 'user.registered'
Run Code Online (Sandbox Code Playgroud)
然而,这也带来了一些警告:
x.y.z
符号,但数组处理却不清楚。然而,您可以简单地将其展平为搜索索引的记录集,即如果user.role
是[developer, engineer]
,您可以为搜索索引创建两个记录,(<id>, 'user.role', 'developer')
并且(<id>, 'user.role', 'engineer')
。第三个表是复制的event_def
,但在现实中完全没有用。有可能,如果工程师查看日志,他根本不需要格式化,并且如果将它们呈现给最终用户,他们将通过应用程序获得,并且直接编译格式化定义要容易得多进入应用程序。
归档时间: |
|
查看次数: |
13245 次 |
最近记录: |