- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
TL;DR 在底部。
我继承了一个设计相当糟糕的表,其中保存了针对第三方网络服务的请求日志。该表包含一个时间戳、两个名为metadata_1 和metadata_2 的字段(允许您识别用户)以及一个名为TEXT 的超长VARCHAR2 字段。
此文本字段保存实际的请求信息,表示为逗号分隔的值列表。此列表中隐藏着两个相关的信息,我将其称为“请求类型”和“请求 key ”。我试图找出每个用户的不成功请求与每天总请求的比率以及请求 key 。然后将该值与当天的全局错误率进行比较,以识别与网络服务通信时遇到问题的设备。 (元数据仅标识用户,因此访问他们的设备需要一些额外的工作。)不成功的请求有一个我称之为“错误类型”的字段,该字段插入在请求类型之前。
正如您可能从最后一句中猜到的那样,这个以逗号分隔的值列表的格式不一致。特别是,逗号分隔列表中 KEY 字段的位置取决于请求类型,而请求类型的位置又取决于请求是否成功。所有这些字段都是可变长度的。
因此 TEXT 字段可能如下所示:
"2017-04-05T07:21:00.569Z,html_error:403,get_status,80,asdf2k,1,0,KEY_123,hunter2"
"2017-04-05T07:21:01.529Z,html_error:403,get_status,80,asdf2k,1,0,KEY_123,hunter2"
但它也可能看起来像这样:
"2017-04-05T07:23:46.459Z,send_events,80,qwert-8,2,1,KEY_123,foobar,1,1,false,114,11838"
我的问题是:您将如何解决这个问题?有一个查询可以在测试环境中运行,如下所示,但其性能极差。必须有更好的方法来做到这一点。假设这一切都必须在单个查询中完成,并且我对环境或数据库设计没有影响。 (请注意,这里进行了一些额外的过滤。任何其他看起来奇怪的事情都可能是我在匿名化过程中犯的错误。这更多的是关于我正在使用的策略 - 我不是要求您为我编写查询。 )
<小时/>期望结果:对于每个用户、日期和请求 key ,成功和不成功请求的数量与当天成功请求的比例相比。
当前结果:如上所述,但性能 Not Acceptable 。
select a.*, b.success_rate_day from (select device.serial_id, rql.date, rql.KEY, rql.requests_ok, rql.requests_error
from device, user,
(select request_log.meta_1, request_log.meta_2, to_char(request_log.created_timestamp, 'DDD') AS date,
(select count(b.TEXT)
FROM request_log b
where b.meta_1 = request_log.meta_1
and b.meta_2 = request_log.meta_2
and b.text NOT LIKE '%error%'
and to_char(request_log.created_timestamp, 'DDD') = to_char(b.created_timestamp, 'DDD')
and (CASE
WHEN b.TEXT LIKE '%html_error%' THEN SUBSTR(b.TEXT, INSTR(b.TEXT, ';', -1, 2)+1, (INSTR(b.TEXT, ';', -1, 1)-INSTR(b.TEXT, ';', -1, 2)-1))
WHEN b.TEXT LIKE '%get_status%' THEN SUBSTR(b.TEXT, INSTR(b.TEXT, ';', -1, 4)+1, (INSTR(b.TEXT, ';', -1, 3)-INSTR(b.TEXT, ';', -1, 4)-1))
WHEN b.TEXT LIKE '%send_events%' THEN SUBSTR(b.TEXT, INSTR(b.TEXT, ';', 1, 6)+1, INSTR(b.TEXT, ';', 1, 7)-INSTR(b.TEXT, ';', 1, 6)-1)
ELSE 'Error'
END) = (CASE
WHEN request_log.TEXT LIKE '%html_error%' THEN SUBSTR(request_log.TEXT, INSTR(request_log.TEXT, ';', -1, 2)+1, (INSTR(request_log.TEXT, ';', -1, 1)-INSTR(request_log.TEXT, ';', -1, 2)-1))
WHEN request_log.TEXT LIKE '%get_status%' THEN SUBSTR(request_log.TEXT, INSTR(request_log.TEXT, ';', -1, 4)+1, (INSTR(request_log.TEXT, ';', -1, 3)-INSTR(request_log.TEXT, ';', -1, 4)-1))
WHEN request_log.TEXT LIKE '%send_events%' THEN SUBSTR(request_log.TEXT, INSTR(request_log.TEXT, ';', 1, 6)+1, INSTR(request_log.TEXT, ';', 1, 7)-INSTR(request_log.TEXT, ';', 1, 6)-1)
ELSE 'Error'
END)
) AS requests_ok,
(select count(b.TEXT)
FROM request_log b
where b.meta_1 = request_log.meta_1
and b.meta_2 = request_log.meta_2
and b.text LIKE '%error%'
and to_char(request_log.created_timestamp, 'DDD') = to_char(b.created_timestamp, 'DDD')
and (CASE
WHEN b.TEXT LIKE '%html_error%' THEN SUBSTR(b.TEXT, INSTR(b.TEXT, ';', -1, 2)+1, (INSTR(b.TEXT, ';', -1, 1)-INSTR(b.TEXT, ';', -1, 2)-1))
WHEN b.TEXT LIKE '%get_status%' THEN SUBSTR(b.TEXT, INSTR(b.TEXT, ';', -1, 4)+1, (INSTR(b.TEXT, ';', -1, 3)-INSTR(b.TEXT, ';', -1, 4)-1))
WHEN b.TEXT LIKE '%send_events%' THEN SUBSTR(b.TEXT, INSTR(b.TEXT, ';', 1, 6)+1, INSTR(b.TEXT, ';', 1, 7)-INSTR(b.TEXT, ';', 1, 6)-1)
ELSE 'Error'
END) = (CASE
WHEN request_log.TEXT LIKE '%html_error%' THEN SUBSTR(request_log.TEXT, INSTR(request_log.TEXT, ';', -1, 2)+1, (INSTR(request_log.TEXT, ';', -1, 1)-INSTR(request_log.TEXT, ';', -1, 2)-1))
WHEN request_log.TEXT LIKE '%get_status%' THEN SUBSTR(request_log.TEXT, INSTR(request_log.TEXT, ';', -1, 4)+1, (INSTR(request_log.TEXT, ';', -1, 3)-INSTR(request_log.TEXT, ';', -1, 4)-1))
WHEN request_log.TEXT LIKE '%send_events%' THEN SUBSTR(request_log.TEXT, INSTR(request_log.TEXT, ';', 1, 6)+1, INSTR(request_log.TEXT, ';', 1, 7)-INSTR(request_log.TEXT, ';', 1, 6)-1)
ELSE 'Error'
END)
) AS requests_error,
(CASE
WHEN TEXT LIKE '%html_error%' THEN SUBSTR(TEXT, INSTR(TEXT, ';', -1, 2)+1, (INSTR(TEXT, ';', -1, 1)-INSTR(TEXT, ';', -1, 2)-1))
WHEN TEXT LIKE '%get_status%' THEN SUBSTR(TEXT, INSTR(TEXT, ';', -1, 4)+1, (INSTR(TEXT, ';', -1, 3)-INSTR(TEXT, ';', -1, 4)-1))
WHEN TEXT LIKE '%send_events%' THEN SUBSTR(TEXT, INSTR(TEXT, ';', 1, 6)+1, INSTR(TEXT, ';', 1, 7)-INSTR(TEXT, ';', 1, 6)-1)
ELSE 'Error'
END) AS KEY
from request_log
where request_log.meta_1 <= 99999
and extract(hour from request_log.created_timestamp) BETWEEN 5 AND 23
group by request_log.meta_1,
request_log.meta_2,
to_char(request_log.created_timestamp, 'DDD'),
(CASE
WHEN TEXT LIKE '%html_error%' THEN SUBSTR(TEXT, INSTR(TEXT, ';', -1, 2)+1, (INSTR(TEXT, ';', -1, 1)-INSTR(TEXT, ';', -1, 2)-1))
WHEN TEXT LIKE '%get_status%' THEN SUBSTR(TEXT, INSTR(TEXT, ';', -1, 4)+1, (INSTR(TEXT, ';', -1, 3)-INSTR(TEXT, ';', -1, 4)-1))
WHEN TEXT LIKE '%send_events%' THEN SUBSTR(TEXT, INSTR(TEXT, ';', 1, 6)+1, INSTR(TEXT, ';', 1, 7)-INSTR(TEXT, ';', 1, 6)-1)
ELSE 'Error'
END)
) rql
where (device.user_ID = user.id)
and (user.meta_1 = rql.meta_1)
and (user.meta_2 = rql.meta_2)) a,
(select rql_global.date, rql_global.success_rate_day
from (select to_char(request_log.created_timestamp, 'DDD') AS date, ROUND(
(select count(b.TEXT) FROM request_log b where b.meta_1 <= 99999 and extract(hour from b.created_timestamp) BETWEEN 5 AND 23 and b.text NOT LIKE '%error%' and to_char(request_log.created_timestamp, 'DDD') = to_char(b.created_timestamp, 'DDD'))
/
GREATEST((select count(c.TEXT) FROM request_log c where c.meta_1 <= 99999 and extract(hour from c.created_timestamp) BETWEEN 5 AND 23 and to_char(request_log.created_timestamp, 'DDD') = to_char(c.created_timestamp, 'DDD')), 1), 4) *100
AS success_rate_day
from request_log
group by to_char(request_log.created_timestamp, 'DDD')
) rql_global) b
where a.date = b.date
order by serial_id ASC, a.date ASC, KEY ASC;
最佳答案
我认为这可以重写如下:
WITH log_info AS (SELECT meta_1,
meta_2,
to_char(created_timestamp, 'DDD') dt,
CASE
WHEN TEXT LIKE '%html_error%' THEN SUBSTR(TEXT, INSTR(TEXT, ';', -1, 2)+1, (INSTR(TEXT, ';', -1, 1)-INSTR(TEXT, ';', -1, 2)-1))
WHEN TEXT LIKE '%get_status%' THEN SUBSTR(TEXT, INSTR(TEXT, ';', -1, 4)+1, (INSTR(TEXT, ';', -1, 3)-INSTR(TEXT, ';', -1, 4)-1))
WHEN TEXT LIKE '%send_events%' THEN SUBSTR(TEXT, INSTR(TEXT, ';', 1, 6)+1, INSTR(TEXT, ';', 1, 7)-INSTR(TEXT, ';', 1, 6)-1)
ELSE 'Error'
END key_val
FROM request_log
where request_log.meta_1 <= 99999
and extract(hour from request_log.created_timestamp) BETWEEN 5 AND 23),
li AS (SELECT meta_1,
meta_2,
dt,
key_val,
COUNT(CASE WHEN text NOT LIKE '%error%' THEN 1 END) requests_ok,
COUNT(CASE WHEN text LIKE '%error%' THEN 1 END) requests_error,
COUNT(*) total_requests
FROM log_info
GROUP BY meta_1,
meta_2,
dt,
key_val),
rl AS (SELECT meta_1,
meta_2,
dt,
key_val,
requests_ok,
requests_error,
SUM(requests_error) OVER (PARTITION BY dt) requests_error_by_ddd,
SUM(total_requests) OVER (PARTITION BY dt) total_requests_by_ddd
FROM li)
SELECT d.serial_id,
rql.date,
rql.key,
rql.requests_ok,
rql.requests_error,
ROUND(100 * reqests_error_by_ddd/greatest(total_requests_by_ddd, 1), 2) success_rate_day
FROM device d
INNER JOIN usr u ON d.user_id = u.id
INNER JOIN rl ON u.meta_1 = rl.meta_1
AND u.meta_2 = rl.meta_2;
不过,您必须检查我是否设法使逻辑正确。
首先,您在各处重复键的 case 语句,因此我将其提取到一个单独的子查询中 ( log_info
)。
接下来,您似乎想要进行条件计数,因此我没有使用单独的标量子查询来获取计数,而是使用大小写来限制我想要计数的行(空值不会得到)包含在计数中)。这是在 li
子查询中完成的。
然后,您似乎需要获取每天的总请求数和总错误请求数,因此我使用了分析 sum() 函数将同一天所有行的信息汇总在一起 - 这是在 rl
子查询中完成的.
然后,在最终查询中,我执行与其他表的联接以及 success_rate_day 计算。请注意,我将连接从旧式语法转换为 ANSI 连接语法。
假设我的逻辑确实正确,这应该比您当前的查询性能更高。如果我的逻辑错误,希望您能够相应地修改我的查询。
我还加入了我的声音,建议优化表格,将信息拉到自己单独的列中 *{;-)
关于sql - 有没有办法针对 SQL-CSV-Antipattern 编写 'good' 查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44138430/
我有三张 table 。表 A 有选项名称(即颜色、尺寸)。表 B 有选项值名称(即蓝色、红色、黑色等)。表C通过将选项名称id和选项名称值id放在一起来建立关系。 我的查询需要显示值和选项的名称,而
在mysql中,如何计算一行中的非空单元格?我只想计算某些列之间的单元格,比如第 3-10 列之间的单元格。不是所有的列...同样,仅在该行中。 最佳答案 如果你想这样做,只能在 sql 中使用名称而
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 7 年前。 Improve this ques
我正在为版本7.6进行Elasticsearch查询 我的查询是这样的: { "query": { "bool": { "should": [ {
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 7 年前。 Improve this ques
是否可以编写一个查询来检查任一子查询(而不是一个子查询)是否正确? SELECT * FROM employees e WHERE NOT EXISTS (
我找到了很多关于我的问题的答案,但问题没有解决 我有表格,有数据,例如: Data 1 Data 2 Data 3
以下查询返回错误: 查询: SELECT Id, FirstName, LastName, OwnerId, PersonEmail FROM Account WHERE lower(PersonEm
以下查询返回错误: 查询: SELECT Id, FirstName, LastName, OwnerId, PersonEmail FROM Account WHERE lower(PersonEm
我从 EditText 中获取了 String 值。以及提交查询的按钮。 String sql=editQuery.getText().toString();// SELECT * FROM empl
我有一个或多或少有效的查询(关于结果),但处理大约需要 45 秒。这对于在 GUI 中呈现数据来说肯定太长了。 所以我的需求是找到一个更快/更高效的查询(几毫秒左右会很好)我的数据表大约有 3000
这是我第一次使用 Stack Overflow,所以我希望我以正确的方式提出这个问题。 我有 2 个 SQL 查询,我正在尝试比较和识别缺失值,尽管我无法将 NULL 字段添加到第二个查询中以识别缺失
什么是动态 SQL 查询?何时需要使用动态 SQL 查询?我使用的是 SQL Server 2005。 最佳答案 这里有几篇文章: Introduction to Dynamic SQL Dynami
include "mysql.php"; $query= "SELECT ID,name,displayname,established,summary,searchlink,im
我有一个查询要“转换”为 mysql。这是查询: select top 5 * from (select id, firstName, lastName, sum(fileSize) as To
通过我的研究,我发现至少从 EF 4.1 开始,EF 查询上的 .ToString() 方法将返回要运行的 SQL。事实上,这对我来说非常有用,使用 Entity Framework 5 和 6。 但
我在构造查询来执行以下操作时遇到问题: 按activity_type_id过滤联系人,仅显示最近事件具有所需activity_type_id或为NULL(无事件)的联系人 表格结构如下: 一个联系人可
如何让我输入数据库的信息在输入数据 5 分钟后自行更新? 假设我有一张 table : +--+--+-----+ |id|ip|count| +--+--+-----+ |
我正在尝试搜索正好是 4 位数字的 ID,我知道我需要使用 LENGTH() 字符串函数,但找不到如何使用它的示例。我正在尝试以下(和其他变体)但它们不起作用。 SELECT max(car_id)
我有一个在 mysql 上运行良好的 sql 查询(查询 + 连接): select sum(pa.price) from user u , purchase pu , pack pa where (
我是一名优秀的程序员,十分优秀!