MySQL JSON_EXTRACT性能

时间:2017-09-26 13:08:09

标签: mysql nosql

我们有一个日志记录表,随着新事件的发生而增长。目前,我们存储了大约120.000行日志事件。

事件表如下所示:

'CREATE TABLE `EVENTS` (
`ID` int(11) NOT NULL AUTO_INCREMENT, 
`EVENT` varchar(255) NOT NULL, 
`ORIGIN` varchar(255) NOT NULL,
`TIME_STAMP` TIMESTAMP NOT NULL, 
`ADDITIONAL_REMARKS` json DEFAULT NULL, 
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=137007 DEFAULT CHARSET=utf8'

Additional_Remarks是一个JSON字段,因为不同的应用程序登录到此表并可以向发生的事件添加更多信息。我不想在这里放任何数据结构,因为这些信息可能不同。例如,一个项目管理应用程序可以记录:

ID, "new task created", "app", NOW(), {"project": {"id": 1}, "creator": {"id": 1}}

虽然其他应用程序没有项目或创建者,但也许他们想要存储在Additional_Remarks字段中的猫和所有者。

查询可以使用Additional_Remarks字段过滤某个特定应用程序的信息,如:

SELECT
DISTINCT(ADDITIONAL_REMARKS->"$.project.id") as 'project',
COUNT(CASE WHEN EVENT = 'new task created' THEN 1 END) AS 'new_task'
FROM EVENTS
WHERE DATE(TIMESTAMP) >= DATE(NOW()) - INTERVAL 30 DAY
AND ORIGIN = "app"
GROUP BY project
ORDER BY new_task DESC
LIMIT 10;

输出EXPLAIN查询:

'1', 'SIMPLE', 'EVENTS', NULL, 'ALL', NULL, NULL, NULL, NULL, '136459', '100.00', 'Using where; Using temporary; Using filesort'

通过此查询,我获得了过去30天内创建的任务最多的前10个项目。工作正常,但随着表的增长,这些查询变得越来越慢。对于120.000行,此查询需要超过30秒。

你知道提高速度的方法吗?表中id最高的最新信息比旧条目更重要。通常我只查看过去X天发生的条目。在第一个条目从where子句开始的X天之后停止查询会很有用,因为所有其他条目都更旧。

2 个答案:

答案 0 :(得分:1)

如果对TIME_STAMP编制索引,则DATE函数将不允许使用索引,因为它是不确定的。

WHERE DATE(TIMESTAMP) >= DATE(NOW()) - INTERVAL 30 DAY

可以改写为。

 WHERE TIMESTAMP >= UNIX_TIMESTAMP(DATE(NOW()) - INTERVAL 30 DAY)
  

你知道提高速度的方法吗?

我能看到加速查询的唯一方法是多列索引TIMESTAMP和ORIGIN,如ALTER TABLE EVENTS ADD KEY timestamp_origin (TIME_STAMP, ORIGIN);和我的查询调整

修改

传递的表可以提高查询速度,因为它将使用新索引。

SELECT 
  ADDITIONAL_REMARKS->"$.project.id" AS 'project',
  COUNT(CASE WHEN EVENT = 'new task created' THEN 1 END) AS 'new_task'
FROM ( 

  SELECT 
   *
  FROM EVENTS 
  WHERE
    TIME_STAMP >= UNIX_TIMESTAMP(DATE(NOW()) - INTERVAL 30 DAY)
  AND
    ORIGIN = "app"
) 
 AS events_within_30_days

GROUP BY project
ORDER BY new_task DESC
LIMIT 10;    

答案 1 :(得分:0)

我已经减少了行数的内部选择可以将查询时间从30秒减少到0.05秒。

看起来像:

SELECT 
ADDITIONAL_REMARKS->"$.project.id" AS 'project',  
COUNT(CASE WHEN EVENT = 'new task created' THEN 1 END) AS 'new_task'
FROM ( 

SELECT *   
   FROM EVENTS    WHERE
   EVENT = 'new task created'
   AND TIME_STAMP >= UNIX_TIMESTAMP(DATE(NOW()) - INTERVAL 30 DAY)   
   AND ORIGIN = "app" )   AS events_within_30_days

GROUP BY project 
ORDER BY new_task DESC 
LIMIT 10;