OQL查询语言
使用OQL可以对复杂的对象进行内容提取,例如做了2级缓存时,想要核对内存中的缓存和Redis是否一致时就需要OQL,方便后续的统计分析。
List数据类型
以下面的ArrayList类型的数据为例,右键Copy -> OQL Query,会自动为剪贴板一个查询语句SELECT * FROM OBJECTS 4045754,在这个语句的基础上进行查询。其中elementData[0:-1]用来对数组类型数据进行展开,然后在外层返回RosVo对象的数组,可以直接AS加别名(不能省略),通过.的方式来获取值。
需要注意的是,OQL不支持在table[0:-1]展开数组数据时直接进行数据的获取,所有的查询全部需要嵌套子查询来实现
SELECT toString(data.ruleId) FROM OBJECTS ( SELECT elementData[0:-1] AS data FROM OBJECTS 4045754 )
Map数据类型
以上一篇文章的Fact对象举例:
SELECT toString(n.key), toString(n.value) FROM OBJECTS ( SELECT OBJECTS table.@referenceArray FROM OBJECTS ( SELECT OBJECTS values FROM ".*Fact" ) ) n
# 带条件查询
SELECT toString(n.key), toString(n.value) FROM OBJECTS ( SELECT OBJECTS table.@referenceArray FROM OBJECTS ( SELECT OBJECTS values FROM ".*Fact" ) ) n WHERE (toString(n.key) = "metric_value")
Map、List、Set嵌套
我的应用中有一个较为复杂的对象CepExecutorCache,其中定义了一个静态成员变量
Map<String, List<Map<String, Map<String, Map<String, Set<String>>>>>> instanceMap = new ConcurrentHashMap<>()
SELECT toString(k1), toString(k2), toString(k3), toString(t.key), t.value FROM OBJECTS ( SELECT k AS k1, key AS k2, t.key AS k3, t.value.map.table[0:-1] AS t FROM OBJECTS ( SELECT k, key, t.key, t.value.table[0:-1] AS t FROM OBJECTS ( SELECT k AS k, t.key AS key, t.value.table[0:-1] AS t FROM OBJECTS ( SELECT key AS k, val.table[0:-1] AS t FROM OBJECTS ( SELECT d.key AS key, d.val[0:-1] AS val FROM OBJECTS ( SELECT OBJECTS c[0:-1] FROM OBJECTS ( SELECT OBJECTS instanceMap FROM OBJECTS ".*.CepExecutorCache" ) c ) d ) ) ) ) )
单个Map数据
由于Map存在hash冲突的时候会给链表添加数据,即Map的next属性,所以有事需要多次进行查询,此处简单说明
# 最外层ObjectId
SELECT k FROM OBJECTS ( SELECT toString(t.key) AS k FROM OBJECTS ( SELECT table[0:-1] AS t FROM OBJECTS 2323754 ) ) WHERE (k != "null")
# 里层1-6层
SELECT k FROM OBJECTS ( SELECT toString(t1.key) AS k FROM OBJECTS ( SELECT t.next.next.next.next.next.next AS t1 FROM OBJECTS ( SELECT table[0:-1] AS t FROM OBJECTS 2323754 ) ) ) WHERE (k != "null")
# 最外层数量
# 2323754为objectTags对象,copy OQL
SELECT k, toString(t1.key), t1.value FROM OBJECTS ( SELECT toString(t.key) AS k, t.value.table[0:-1] AS t1 FROM OBJECTS ( SELECT table[0:-1] AS t FROM OBJECTS 2323754 ) ) WHERE (toString(t1.key) != "null")
#控制里层next数量为1-6层的数据
SELECT k, toString(t.key), t.value FROM OBJECTS ( SELECT toString(t1.key) AS k, t1.value.table[0:-1] AS t FROM OBJECTS ( SELECT t.next.next.next.next.next.next AS t1 FROM OBJECTS ( SELECT table[0:-1] AS t FROM OBJECTS 2323754 ) ) ) WHERE (toString(t.key) != "null")
堆内存分代对象查询
新生代、s0、老年代的地址信息可以在GC日志中找到,通过日志的地址来调整OQL查询语句。 例如以下GC日志片段:
Heap after GC invocations=3572 (full 13):
PSYoungGen total 1275904K, used 142080K [0x0000000740000000, 0x00000007c0000000, 0x00000007c0000000)
eden space 1133568K, 0% used [0x0000000740000000,0x0000000740000000,0x0000000785300000)
from space 142336K, 99% used [0x0000000785300000,0x000000078ddc0130,0x000000078de00000)
to space 497152K, 0% used [0x00000007a1a80000,0x00000007a1a80000,0x00000007c0000000)
ParOldGen total 4194304K, used 2480450K [0x0000000640000000, 0x0000000740000000, 0x0000000740000000)
object space 4194304K, 59% used [0x0000000640000000,0x00000006d7650838,0x0000000740000000)
Metaspace used 1137502K, capacity 1225308K, committed 1226200K, reserved 2107392K
class space used 146701K, capacity 169040K, committed 169176K, reserved 1048576K
}
# 新生代
SELECT * FROM instanceof "java.lang.Object" t WHERE toHex(t.@objectAddress) <= "0x7c0000000" AND toHex(t.@objectAddress) >= "0x740000000"
# s0即from区
SELECT * FROM instanceof "java.lang.Object" t WHERE toHex(t.@objectAddress) <= "0x785300000" AND toHex(t.@objectAddress) >= "0x740000000"
# 老年代
SELECT * FROM instanceof "java.lang.Object" t WHERE toHex(t.@objectAddress) <= "0x740000000" AND toHex(t.@objectAddress) >= "0x640000000"