清除过滤器
文章
Hao Ma · 三月 26, 2021
Intersystems IRIS 是开发、运行和消耗数据科学服务的绝佳平台。 IRIS 可以使用适配器从任何类型、格式、协议和时间提取数据。 这些数据集可以通过 BPL、DTL 和 Object Script 准备,并存储为 SQL 或 NoSQL 数据。 最后,它可以被 IRIS 内部的开放 ML 算法所消耗,并在 IRIS 仪表板中可视化。 了解详情:[https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=PAGE\_data\_science](https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=PAGE_data_science)。
公告
Claire Zheng · 九月 27, 2022
社区成员们,大家好!
我们开心地宣布一种全新类型的比赛——寻找最聪明的创意比赛!欢迎了解:
💡 InterSystems Idea 创意马拉松 💡
在9月26日至10月16日期间提出一个与InterSystems产品和服务相关的想法,即可获得达成奖。
最重要的是,此次赛事InterSystems的员工和社区成员都可以参与!
>> 点击提交你的想法吧! <<
规则
InterSystems Idea创意马拉松是由InterSystems Ideas反馈门户组织的,在InterSystems Ideas反馈门户,您可以提交与我们的服务(文档、开发社区、全球大师等)相关的产品增强请求和想法,并投票选出您喜欢的。
在本次比赛中,我们邀请大家在这个门户网站上分享自己的想法,并为他人投票。
只需在 InterSystems Ideas网站 提交想法即可参赛。
合格的参赛创意应符合:
用户在Idea-A-Thon创意马拉松期间提交,由通过InterSystems Ideas网站注册的用户创建(您可以通过InterSystems SSO登录);
不要成为其他已经存在的想法的一部分——只允许新的想法;
不描述InterSystems产品或服务的现有功能;
除了标题之外,还要对观点的本质进行详细而清晰的解释;
以英文发帖;
被专家认为是有意义的。
所有符合条件的想法将在InterSystems ideas门户网站上拥有一个特殊的“Idea-A-Thon”状态,可以很容易地在Idea创意马拉松上找到。
谁可以参加?
我们邀请所有人加入我们的创意马拉松。欢迎InterSystems员工和社区成员参与并提交创意想法。
奖项
1. 参与奖 :每个发布合格想法的人都会将获得奖励:
🎁 InterSystems Branded T-Shirt
2. 专家奖:获胜者将由InterSystems专家团队选出,并将获得:
🎁 LEGO Star Wars™ R2-D2™ / BOSE Sleepbuds™ II / BOSE SoundLink Flex Bluetooth® speaker bundle
3. 社区奖:获得最多投票的创意,获奖者将获得:
🎁 LEGO Star Wars™ R2-D2™ / BOSE Sleepbuds™ II / BOSE SoundLink Flex Bluetooth® speaker bundle
重要提示:InterSystems的员工只能获得参与奖。专家奖和社区奖只能由非intersystems社区成员获得。
参赛时间
📝 9月26日 - 10月16日:创意发布、投票阶段
在此期间发布一个或几个创意。InterSystems Ideas网站的注册会员可以为发表的创意投票,这些投票将计入社区奖。
注意:越早发表你的创意,你就越有更多的时间去收集投票。
来参加吧!
来 InterSystems Ideas 发布你的创意拿大奖!时刻关注你的创意!
祝大家好运 👍
Important note: All prizes are subject to availability and shipping options. Some items may not be available to ship internationally to specific countries. Prizes cannot be delivered to residents of Crimea, Russia, Belarus, Iran, North Korea, Syria, or other US-embargoed countries. We will let you know if a prize is not available and offer a possible replacement.
重要提示:所有奖品均受可用性和运输选择。有些项目可能无法国际运输到特定国家。奖品不能发放给克里米亚、俄罗斯、白俄罗斯、伊朗、朝鲜、叙利亚或其他美国禁运国家的居民。如果没有奖品,我们将告知您,并提供可替代品。
公告
Claire Zheng · 一月 30, 2023
亲爱的开发者们,
非常感谢您又在 InterSystems 开发者社区度过了一年!
我们的团队日复一日地努力让它变得更好,这对我们12000+ 每一位成员都很重要!
我们想知道目前开发者社区对您有多大用处。请花点时间让我们了解您的想法,以及可以改进的地方:
👉🏼 InterSystems 开发者社区2022年度调查 👈🏼
请知悉:调查可在 5 分钟内完成。
也欢迎您在本文的评论部分提供反馈。
我们期待了解您的意见! 😉
公告
Claire Zheng · 十一月 17, 2022
Hi 开发者社区的成员们,大家好!
欢迎关注我们第一期 InterSystems Ideas News!
最重要的消息是我们第一次非常成功的 创意马拉松。我们收到了75个有趣的新想法。
以下是创意社区(Ideas Portal)一些数据:
✓ 上月,我们收到了42条新创意✓ 上月,我们迎来了147位新用户✓ 迄今为止,我们共收到142 条新创意✓ 迄今为止,共有 273 位用户加入我们
以下是评选出来的当月最佳创意的前5名:
IRIS and ZPM(Open Exchange) integration
Move users, roles, resources, user tasks, Mappings (etc) to a seperate Database, other than %SYS, so these items can be mirrored
RPMShare - Database solution for remote patient monitoring (RPM) datasets of high density vitals
Create front-end package based on CSS and JS to be used in NodeJS and Angular projects
PM platform
这里是上个月发布的所有想法的列表
目前就这些啦!
访问我们的 InterSystems Ideas portal(创意社区),提出你的观点,为你认同的创意投票!
下期见!
公告
Michael Lei · 一月 27, 2023
大家好,
我在 OEX 上加载了一个新软件包,我也计划在本月参加比赛。
简而言之,它为您提供以下内容。
用于 InterSystems IRIS 的持久(表)类以保存记录历史的基类
这些类允许在touch时将持久类记录历史化到另一个持久类中。
这提供了任何记录的完整历史记录。
它允许记录回滚到特定版本。
它可以自动清除旧的历史记录。
请检查一下。
谢谢你们。
公告
Claire Zheng · 四月 19, 2023
为支持医疗信息行业人才发展,InterSystems 为中国市场量身定制了贴近需求、灵活、实操性强的技术认证培训计划,由 InterSystems 资深技术专家亲自授课,帮助用户快速掌握 InterSystems 技术,确保用户从快速发展的 InterSystems 技术中获益,以更好地服务于医院信息化建设。点击此处查看课程详情:InterSystems中国技术培训认证
您的最佳学习路径
为什么要参加 InterSystems 技术认证培训?
InterSystems 数据平台技术已成为国内医疗信息化领域的主流技术之一,支持全国数百家大型公立医院核心系统长期稳定运行 20 余年;
专为中国技术用户量身定制,具有贴近需求、灵活、实操性强等特点;
InterSystems 资深技术专家亲自授课,帮助用户快速掌握 InterSystems 技术及最佳实践;
InterSystems 官方技术认证培训具备更高权威性,可以助力用户更好地运用 InterSystems 技术,并从快速发展的 InterSystems 技术中获益,保持技术先进性。
哪些用户可以参加认证培训?
凡使用 InterSystems 技术或对 InterSystems 技术感兴趣的IT从业人员或机构均可参加。
您可以从技术认证培训中获得哪些技能和成长?
与时俱进的课程更新,理论与实践相结合的学习方式,可以帮助您持续提升对 InterSystems 技术的掌握;
参与 InterSystems 的分级培训计划,考核通过即可获得认证证书;
通过线下课程与活动,拓展技术人脉。
InterSystems 中国的认证培训讲师团成员是哪些?
InterSystems 中国资深工程师团队授课。
报名方式及开课时间是如何安排的?
报名人数满 5 人即开班,每季度一次,培训方式为线下培训,考试内容含书面测试与上机实践。课程收费请咨询您的 InterSystems 客户经理。医院及医疗信息化企业推荐以机构方式参与培训。
如需报名或咨询更多详情,请联系您的 InterSystems 客户经理,或通过以下方式与 InterSystems 中国团队联系:
电话:400-601-9890
邮件:GCDPsales@InterSystems.com
文章
Jingwei Wang · 七月 28, 2022
定义 Stored Procedures
可以使用以下方式定义stored procedures
使用DDL定义存储过程
使用类方法定义存储过程
使用DDL定义存储过程
CREATE PROCEDURE 可以创建一个查询,它总是作为一个存储过程被预测。一个查询可以返回一个单一的结果集。
CREATE PROCEDURE AgeQuerySP(IN topnum INT 10, IN minage INT 20)
BEGIN
SELECT TOP :topnum Name, Age FROM Sample.Person
WHERE Age > :minage;
END
列表中的每个参数声明包括(按顺序)。指定参数模式是IN(输入值),OUT(输出值),还是INOUT(修改值)。如果省略,默认的参数模式是IN,参数名称是区分大小写的。
CREATE QUERY 可以创建一个可以选择作为存储过程投射的查询。一个查询可以返回一个单一的结果集,这个查询可能是也可能不是作为存储过程公开的。要创建一个作为存储过程公开的查询,你必须指定PROCEDURE关键字作为其特征之一。你也可以使用CREATE PROCEDURE语句来创建一个作为存储过程公开的查询。
为了创建一个查询,你必须拥有%CREATE_QUERY管理权限,正如GRANT命令所指定的那样。如果类的定义是一个已部署的类,你不能在该类中创建一个查询。
CREATE QUERY AgeQuery(IN topnum INT DEFAULT 10,IN minage INT 20)
PROCEDURE
BEGIN
SELECT TOP :topnum Name,Age FROM Sample.Person
WHERE Age > :minage ;
END
使用类定义存储过程
要定义一个方法存储过程,只需定义一个类方法并设置其SqlProc关键字。
Class MyApp.Person Extends %Persistent [DdlAllowed]
{
/// This procedure finds total sales for a territory
ClassMethod FindTotal(territory As %String) As %Integer [SqlProc]
{
// use embedded sql to find total sales
&sql(SELECT SUM(SalesAmount) INTO :total
FROM Sales
WHERE Territory = :territory
)
Quit total
}
}
这个类被编译后,FindTotal()方法将作为存储过程MyApp.Person_FindTotal()投射到SQL。你可以使用该方法的SqlName关键字改变SQL对存储过程的命名。
该方法使用一个存储过程上下文处理程序,在存储过程和其调用者(例如,ODBC服务器)之间来回传递存储过程上下文。这个过程上下文处理程序是由InterSystems IRIS使用%sqlcontext对象自动生成的(作为%qHandle:%SQLProcContext)。
%sqlcontext由SQLCODE错误状态、SQL行数、错误信息等属性组成,使用相应的SQL变量进行设置,如下所示。
SET %sqlcontext.%SQLCODE=SQLCODE
SET %sqlcontext.%ROWCOUNT=%ROWCOUNT
SET %sqlcontext.%Message=%msg
使用 Stored Procedures
当执行一个以SQL函数为参数的存储过程时,使用CALL来调用该存储过程,如下面的例子.
CALL sp.MyProc(CURRENT_DATE)
SELECT查询不支持执行带有SQL函数参数的存储过程。SELECT支持用一个SQL函数参数执行一个存储函数。
xDBC不支持使用SELECT或CALL来执行一个带有SQL函数参数的存储过程。
你可以在一个SQL查询中使用一个存储函数,就像它是一个内置的SQL函数一样。函数的名称是存储函数的SQL名称(在这里是 "Square"),由定义它的schema(包)名称限定(在这里是 "MyApp")。
下面的查询使用了Square函数。
SELECT Cost, MyApp.Utils_Square(Cost) As SquareCost FROM Products
查询Stored Procedures 信息
INFORMATION.SCHEMA.ROUTINES持久化类显示关于当前命名空间中所有routine和程序的信息。
下面的例子返回routine名称,方法或查询名称,routine类型(PROCEDURE或FUNCTION),routine主体(SQL=带SQL的类查询,EXTERNAL=不带SQL的类查询),返回数据类型,以及当前名称空间中模式 "Sample "中所有routine的routine定义。
SELECTROUTINE_NAME,METHOD_OR_QUERY_NAME,ROUTINE_TYPE,ROUTINE_BODY,SQL_DATA_ACCESS,IS_USER_DEFINED_CAST,
DATA_TYPE||' '||CHARACTER_MAXIMUM_LENGTH AS Returns,NUMERIC_PRECISION||':'||NUMERIC_SCALE ASPrecisionScale,
ROUTINE_DEFINITION
FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA='Sample'
INFORMATION.SCHEMA.PARAMETERS持久化类显示当前命名空间中所有routine和程序的输入和输出参数的信息。
下面的例子返回了当前命名空间中模式 "Sample "中所有routine的routine名称、参数名称、是输入参数还是输出参数,以及参数数据类型信息。
SELECT SPECIFIC_NAME,PARAMETER_NAME,PARAMETER_MODE,ORDINAL_POSITION,
DATA_TYPE,CHARACTER_MAXIMUM_LENGTH AS MaxLen,NUMERIC_PRECISION||':'||NUMERIC_SCALE AS PrecisionScale
FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_SCHEMA='Sample'
文章
Michael Lei · 九月 9, 2021
挑战一:缺乏一个统一的技术体系?InterSystems IRIS 医疗版通过统一的数据库、互操作性/中间件、机器学习和FHIR等医疗行业特有的功能来简化开发,开箱即用。
挑战二:需要高性能的解决方案,可以定制适合医疗行业使用的案例InterSystems IRIS for Health医疗版由医疗行业开发人员创建并为医疗服务服务,具有所需的性能、可扩展性和灵活性,大量的全球、全国大型顶级医院案例。全美排名前20医院,全国客户数百家,百强医院30余家;
挑战三:开源和专有软件缺乏灵活性,无法为医疗行业应用提供高可靠性。InterSystems IRIS医疗版实现一套平台兼容专有和开源模块,同时开发人员可以选择自己喜欢的开发语言和灵活性,支持多种开发语言(ObjectScript,.net, Java, Sql, 等等)
挑战四:缺乏具有医疗卫生领域专业知识的供应商,也没有为开发人员提供持续的支持。InterSystems IRIS 医疗版的产品开发能力、屡获殊荣的支持和长期深耕医疗的企业文化,确保开发人员持续成功。
文章
Claire Zheng · 七月 6, 2021
近日,InterSystems极客俱乐部举办了线上直播“InterSystems Caché系统运维培训”,这是系列视频之一。InterSystems中国资深售前顾问祝麟讲解了“InterSystems Caché系统高可用与数据库镜像”。
文章
Michael Lei · 九月 13, 2022
Globals是InterSystems IRIS的数据持久性的核心。它很灵活,允许存储JSON文档、关系数据、面向对象的数据、OLAP立方体和自定义数据模型,例如思维导图。要了解如何使用globals来存储、删除和获取思维导图数据,请遵循以下步骤:
1. 把repo Clone/git到任意本地目录
$ git clone https://github.com/yurimarx/global-mindmap.git
2. 在该目录下打开Docker 终端并执行:
$ docker-compose build
3. 启动 IRIS 容器:
$ docker-compose up -d
4. 访问 http://localhost:3000 来使用思维导图的前端并创建类似以上的思维导图
本例子的源代码
存储数据 (更多请访问: https://www.npmjs.com/package/mind-elixir):
{
topic: 'node topic',
id: 'bd1c24420cd2c2f5',
style: { fontSize: '32', color: '#3298db', background: '#ecf0f1' },
parent: null,
tags: ['Tag'],
icons: ['😀'],
hyperLink: 'https://github.com/ssshooter/mind-elixir-core',
}
注意parent属性,它被用来在mindmap节点之间建立父/子关系。
使用Globals 来存储思维导图的源代码
ClassMethod StoreMindmapNode
/// Store mindmap node
ClassMethod StoreMindmapNode() As %Status
{
Try {
Set data = {}.%FromJSON(%request.Content)
Set ^mindmap(data.id) = data.id /// set mindmap key
Set ^mindmap(data.id, "topic") = data.topic /// set topic subscript
Set ^mindmap(data.id, "style", "fontSize") = data.style.fontSize /// set style properties subscripts
Set ^mindmap(data.id, "style", "color") = data.style.color
Set ^mindmap(data.id, "style", "background") = data.style.background
Set ^mindmap(data.id, "parent") = data.parent /// store parent id subscript
Set ^mindmap(data.id, "tags") = data.tags.%ToJSON() /// store tags subscript
Set ^mindmap(data.id, "icons") = data.icons.%ToJSON() /// store icons subscript
Set ^mindmap(data.id, "hyperLink") = data.hyperLink /// store hyperLink subscript
Set %response.Status = 200
Set %response.Headers("Access-Control-Allow-Origin")="*"
Write "Saved"
Return $$$OK
} Catch err {
write !, "Error name: ", ?20, err.Name,
!, "Error code: ", ?20, err.Code,
!, "Error location: ", ?20, err.Location,
!, "Additional data: ", ?20, err.Data, !
Return $$$NOTOK
}
}
我们创建了一个名为^mindmap的Global。对于每个思维导图的属性,它被存储在一个Globals下标中。下标的键是mindmap的id属性。
删除思维导图节点的源代码 - kill the global
ClassMethod DeleteMindmapNode
/// Delete mindmap node
ClassMethod DeleteMindmapNode(id As %String) As %Status
{
Try {
Kill ^mindmap(id) /// delete selected mindmap node using the id (global key)
Set %response.Status = 200
Set %response.Headers("Access-Control-Allow-Origin")="*"
Write "Deleted"
Return $$$OK
} Catch err {
write !, "Error name: ", ?20, err.Name,
!, "Error code: ", ?20, err.Code,
!, "Error location: ", ?20, err.Location,
!, "Additional data: ", ?20, err.Data, !
Return $$$NOTOK
}
}
这个例子使用mindmap.id作为mindmap的Global Key,所以删除很容易: call Kill ^mindmap(<mindmap id>)
获得所有存储内容的源代码- 用 $ORDER循环globals
ClassMethod GetMindmap - return all mindmap global nodes
/// Get mindmap content
ClassMethod GetMindmap() As %Status
{
Try {
Set Nodes = []
Set Key = $Order(^mindmap("")) /// get the first mindmap node stored - the root
Set Row = 0
While (Key '= "") { /// while get child mindmap nodes
Do Nodes.%Push({}) /// create a item into result
Set Nodes.%Get(Row).style = {}
Set Nodes.%Get(Row).id = Key /// return the id property
Set Nodes.%Get(Row).hyperLink = ^mindmap(Key,"hyperLink") /// return the hyperlink property
Set Nodes.%Get(Row).icons = ^mindmap(Key,"icons") /// return icons property
Set Nodes.%Get(Row).parent = ^mindmap(Key,"parent") /// return parent id property
Set Nodes.%Get(Row).style.background = ^mindmap(Key,"style", "background") /// return the style properties
Set Nodes.%Get(Row).style.color = ^mindmap(Key,"style", "color")
Set Nodes.%Get(Row).style.fontSize = ^mindmap(Key,"style", "fontSize")
Set Nodes.%Get(Row).tags = ^mindmap(Key,"tags") /// return tags property
Set Nodes.%Get(Row).topic = ^mindmap(Key,"topic") /// return topic property (title mindmap node)
Set Row = Row + 1
Set Key = $Order(^mindmap(Key)) /// get the key to the next mindmap global node
}
Set %response.Status = 200
Set %response.Headers("Access-Control-Allow-Origin")="*"
Write Nodes.%ToJSON()
Return $$$OK
} Catch err {
write !, "Error name: ", ?20, err.Name,
!, "Error code: ", ?20, err.Code,
!, "Error location: ", ?20, err.Location,
!, "Additional data: ", ?20, err.Data, !
Return $$$NOTOK
}
}
用$Order(^mindmap("")) - empty "" - 得到第一个mindmap Global (根节点)。对于每个属性值,我们使用^mindmap(Key,<property name>)。最后,调用$Order(^mindmap(Key))来获得下一个事件。
前端
Mind-elixir和React被用来渲染和编辑mindmap,消耗使用IRIS构建的API后端。见mindmap的反应组件:
Mindmap React component - consuming IRIS REST API
import React from "react";
import MindElixir, { E } from "mind-elixir";
import axios from 'axios';
class Mindmap extends React.Component {
componentDidMount() {
this.dynamicWidth = window.innerWidth;
this.dynamicHeight = window.innerHeight;
axios.get(`http://localhost:52773/global-mindmap/hasContent`)
.then(res => {
if (res.data == "1") {
axios.get(`http://localhost:52773/global-mindmap/get`)
.then(res2 => {
this.ME = new MindElixir({
el: "#map",
direction: MindElixir.LEFT,
data: this.renderExistentMindmap(res2.data),
draggable: true, // default true
contextMenu: true, // default true
toolBar: true, // default true
nodeMenu: true, // default true
keypress: true // default true
});
this.ME.bus.addListener('operation', operation => {
console.log(operation)
if (operation.name == 'finishEdit' || operation.name == 'editStyle') {
this.saveMindmapNode(operation.obj)
} else if (operation.name == 'removeNode') {
this.deleteMindmapNode(operation.obj.id)
}
})
this.ME.init();
})
} else {
this.ME = new MindElixir({
el: "#map",
direction: MindElixir.LEFT,
data: MindElixir.new("New Mindmap"),
draggable: true, // default true
contextMenu: true, // default true
toolBar: true, // default true
nodeMenu: true, // default true
keypress: true // default true
});
this.ME.bus.addListener('operation', operation => {
console.log(operation)
if (operation.name == 'finishEdit' || operation.name == 'editStyle') {
this.saveMindmapNode(operation.obj)
} else if (operation.name == 'removeNode') {
this.deleteMindmapNode(operation.obj.id)
}
})
this.saveMindmapNode(this.ME.nodeData)
this.ME.init();
}
})
}
render() {
return (
<div id="map" style={{ height: window.innerHeight + 'px', width: '100%' }} />
);
}
deleteMindmapNode(mindmapNodeId) {
axios.delete(`http://localhost:52773/global-mindmap/delete/${mindmapNodeId}`)
.then(res => {
console.log(res);
console.log(res.data);
})
}
saveMindmapNode(node) {
axios.post(`http://localhost:52773/global-mindmap/save`, {
topic: (node.topic == undefined ? "" : node.topic),
id: node.id,
style: (node.style == undefined ? "" : node.style),
parent: (node.parent == undefined ? "" : node.parent.id),
tags: (node.tags == undefined ? [] : node.tags),
icons: (node.icons == undefined ? [] : node.icons),
hyperLink: (node.hyperLink == undefined ? "" : node.hyperLink)
})
.then(res => {
console.log(res);
console.log(res.data);
})
}
renderExistentMindmap(data) {
let root = data[0]
let nodeData = {
id: root.id,
topic: root.topic,
root: true,
style: {
background: root.style.background,
color: root.style.color,
fontSize: root.style.fontSize,
},
hyperLink: root.hyperLink,
children: []
}
this.createTree(nodeData, data)
return { nodeData }
}
createTree(nodeData, data) {
for(let i = 1; i < data.length; i++) {
if(data[i].parent == nodeData.id) {
let newNode = {
id: data[i].id,
topic: data[i].topic,
root: false,
style: {
background: data[i].style.background,
color: data[i].style.color,
fontSize: data[i].style.fontSize,
},
hyperLink: data[i].hyperLink,
children: []
}
nodeData.children.push(newNode)
this.createTree(newNode, data)
}
}
}
}
export default Mindmap;
公告
Claire Zheng · 九月 22, 2022
中文社区的同学们大家好!
如你所知,从2022年9月5日-10月24日(北京时间),我们正在举办🏆InterSystems开发者社区中文版首届技术征文大赛🏆(←点击链接进入参赛页面,浏览所有参赛文章)!
截至目前,我们已收获了20余篇佳作
作为此次大赛重要奖项“专家提名奖”评比的重要部分,我们的专家评审团已组建成团!
以下为我们的专家团成员:
@Yunfei.Lei
@Peng.Qiao
@Ida.Yang
@Lin.Zhu
@Louis.Lu
@Hao.Ma
@Jingwei.Wang
@Tete.Zhang
@Tengzhou.Zhuang
@jieliang.liu7848
@Duan.Haihua
@Wenyi.Liu
我们期待专家评审团对参赛作品的公平审阅与打分。
作为社区成员,你的个人贡献也会对每一篇参赛文章产生影响,你的每一次浏览和点赞都将助力你喜欢的文章赢得“开发者社区奖”。
欢迎大家积极投稿、点赞、分享、学习!
欢迎参赛InterSystems开发者社区中文版首届技术征文大赛
公告
Claire Zheng · 九月 2, 2022
2022年9月9日,我们将举办线上“InterSystems 2022全球峰会亮点解读”,点击此处参会。
亮点一:Smart Data Fabric(智能数据编织)
认识Data Fabric(数据编织):概念与应用场景
Data Fabric如何实现高质量数据驱动业务决策?
InterSystems IRIS数据平台提供的Smart Data Fabric解决方案
亮点二:InterSystems IRIS数据平台的三大能力
释放数据价值:通过HL7 FHIR标准支撑CDSS应用和数据探索,使传统数据中心不再受制于特定消息格式,提升医院按需投放数据、释放数据价值的能力。
与Python数据交换:InterSystems IRIS数据平台具有5种与Pyhton数据交互方式,本次研讨会重点介绍DB-API和Embedded Python,并进行实操演示。
列存储:新增的一种数据存储方式,与传统的行存储相比,它将复杂的聚合类分析查询性能提升了一个数量级。
亮点三:HealthShare Health Connect 功能提升
通过HL7 V2 特性提升、数据转换编辑器增强、规则编辑器增强、集成产品扩展架构、接口关系图等,提高实施效率、降低实施成本、提升平台价值。
文章
Michael Lei · 五月 12, 2021
部分 在上个帖子中,我们安排了使用 pButtons 进行 24 小时的性能指标收集。 在本帖中,我们将研究几个收集到的关键指标,以及它们与底层系统硬件的关系。 我们还将开始探索 Caché(或任一 InterSystems 数据平台)指标与系统指标之间的关系。 以及如何使用这些指标来了解系统的每日节拍率并诊断性能问题。
[本系列其他帖子的列表](https://cn.community.intersystems.com/post/intersystems-数据平台的容量规划和性能系列文章)
***2016 年 10 月编辑...*** *[用于将 pButtons 数据提取到 .csv 文件的脚本示例。](https://cn.community.intersystems.com/post/将-pbuttons-数据提取到-csv-文件以便绘制图表)* ***2018 年 3 月编辑...*** 图片消失,重新添加它们。
# 硬件食物群

您将会看到,随着本系列帖子的不断深入,影响性能的服务器组件可以逐项列出:
- CPU
- 内存
- 存储 IO
- 网络 IO
如果这些组件中的任何一个承受压力,那么系统性能和用户体验很可能会受到影响。 这些组件也都相互关联,对一个组件进行更改可能会影响另一个组件,有时会产生意外的后果。 我见过这样一个例子:修复某个存储阵列中的 IO 瓶颈使 CPU 的使用率跳增至 100%,导致用户体验更差,原因是系统突然可以做更多工作,但没有 CPU 资源来为增加的用户活动和吞吐量提供服务。
我们还将了解 Caché 系统活动如何直接影响服务器组件。 如果存储 IO 资源有限,那么可以做出的积极改变是增加系统内存,并增加 __Caché global 缓冲区__的内存,从而降低__系统存储读取 IO__(但可能会增加 CPU 使用率!)。
要定期监视或在用户报告问题时要检查的一个最明显的系统指标是 CPU 使用率。 在 Linux 或 AIX 中查看 _top_ 或 _nmon_,或在 Windows 中查看_性能监视器_。 由于大多数系统管理员会定期查看 CPU 数据,特别是当数据以图形方式呈现时,快速浏览一下就可以很好地了解系统当前的运行状况 - 正常情况或出现活动激增,后者可能是异常情况或表示出现问题。 在本帖中,我们将快速查看 CPU 指标,但会重点关注 Caché 指标,我们首先将查看 _mgstat_ 数据,了解以图形方式表示的数据如何让系统运行状况一目了然。
# mgstat 简介
mgstat 是 pButtons 中包含并在其中运行的一个 Caché 命令。 mgstat 是一个非常好的工具,可收集基本性能指标,帮助您了解系统运行状况。 我们将查看从 24 小时 pButtons 收集的 mgstat 数据,但是,如果您希望捕获 pButtons 之外的数据,也可以根据需要以交互方式运行 mgstat,或者从 Caché 终端将其作为后台作业运行。
要从 %SYS 命名空间按需运行 mgstat,一般格式是:
do mgstat(sample_time,number_of_samples,"/file_path/file.csv",page_length)
例如,运行一小时后台作业,采样周期为 5 秒,然后输出为 csv 文件:
job ^mgstat(5,720,"/data/mgstat_todays_date_and_time.csv")
要显示到屏幕,但丢弃几个列,则输入 dsp132。 给您留个作业,去查看一下输出以了解差异。
do dsp132^mgstat(5,720,"",60)
> mgstat 中的列的详细信息可以在最新的 Caché 文档([InterSystems 在线文档](https://docs.intersystems.com))中的 _Caché 监视指南_中找到
# 查看 mgstat 数据
pButtons 已设计为整理成一个 HTML 文件,以便导航和打包发送给 WRC 支持专家来诊断性能问题。 不过,当您自己运行 pButtons 并想以图形方式显示数据时,可以再次将其拆分为 csv 文件以处理成图形,例如可以使用 Excel、通过命令行脚本或简单的剪切和粘贴来完成。
在本帖中,我们将深入研究几个 mgstat 指标,来说明即使是快速浏览数据,也能让您感觉到系统是否运行良好,或者是否存在会影响用户体验的现有或潜在问题。
## Gloref 和 CPU
下图显示了一个以高事务处理速率运行医院应用程序的站点的数据库服务器 CPU 使用率。 注意活动的高峰期在上午,此时有许多门诊病人,而在午餐时间,活动大幅下降,在下午和晚上则逐渐消失。 此例中的数据来自于 Windows 性能监视器 _(_Total)\% Processor Time_ - 图形的形状符合工作日的情况 - 没有异常的峰值或低谷,所以对这个站点来说是正常的。 通过对您的站点执行相同分析,您可以开始获取“正常”情况的基准。 如果出现大的尖峰,尤其是延长的尖峰,可能说明出现了问题。将来会有一个帖子以 CPU 为重点。

作为参考,该数据库服务器是具有两个 E5-2670 8 核处理器的戴尔 R720,服务器的内存为 128 GB,global 缓冲区为 48 GB。
下图显示了来自 mgstat 的更多数据 — 与 CPU 图形同一天的 Gloref(Global 引用数)或数据库访问量。 Gloref 指示正在发生的工作量,代表当前工作负载;虽然 global 引用会消耗 CPU 时间,但由于 Caché 使用 global 内存缓冲池的方式,这些引用并不始终消耗物理读取等其他系统资源。

在典型的 Caché 应用程序中,Gloref 与 CPU 使用率之间有非常强的相关性。
> 这些 CPU 数据和 gloref 数据所展示出的另一方面是_减少 gloref 将降低 CPU 使用率_,从而可以在核心数较少的服务器上部署或在现有系统上进一步扩展。 还可以通过提高应用程序效率来减少 global 引用,我们将在以后的帖子中重新讨论这个概念。
## PhyRds 和 Rdratio
根据 mgstat 数据 _PhyRds_(物理读取数)和 _Rdratio_(读取比)绘制的图形的形状也可以深入了解系统性能的预期水平,帮助您制定容量计划。 我们将在以后的帖子中深入探讨 Caché 的存储 IO。
_PhyRds_ 只是从磁盘到 Caché 数据库的物理读取 IOPS,您应该看到逻辑磁盘和物理磁盘的操作系统指标中反映了相同的值。 注意,查看操作系统 IOPS 可能还会显示来自非 Caché 应用程序的 IOPS。 不考虑预期的 IOPS 就调整存储大小会导致灾难,您需要了解系统在高峰时段的 IOPS 是多少,才能制定适当的容量计划。 下图显示了午夜零点到 15:30 之间的 _PhyRds_。

注意 05:30 到 10:00 之间的读取数激增。 其他较短的峰值在 11:00 以及 14:00 之前。 您认为这些峰值是由什么引起的? 您的服务器有这些类型的峰值吗?
_Rdratio_ 更有趣一点,它是逻辑块读取数与物理块读取数的比值。 也就是内存中的 global 缓冲区(逻辑)的读取次数与磁盘的读取次数之比,后者的读取速度要慢几个数量级。 _Rdratio_ 高是好事情,但长时间降至接近于零就不好了。

注意读取数高的同时,_Rdratio_ 降至接近于零。 我曾被要求调查过这个站点,当时 IT 部门接到用户电话,报告系统长时间运行缓慢。 当我被要求查看系统时,这种情况已在几个星期内看似随机地出现。
> _**由于 pButtons 已设定为每天 24 小时运行,因此可以相对简单地回溯几周的数据,以查看与支持电话相关的高 _PhyRds_ 和低 _Rdratio_ 的模式。***
经过进一步分析后,原因追溯到一名新的轮班员工身上,他当时运行了多个报告,输入了“错误”参数,加上写得不好的查询,并且没有适当的索引,导致数据库读取数很高。 这就解释了看似随机的缓慢。 由于这些长时间运行的报告将数据读取到 global 缓冲区中,结果是交互用户的数据从物理存储中获取,而不是从内存以及用于为读取提供服务的存储中获取。
监视 _PhyRds_ 和 _Rdratio_ 将让您了解系统的节拍率,也许还可以追踪不良报告或查询。 高 _PhyRds_ 可能有合理的原因 - 也许必须在某个时间运行报告。 使用现代 64 位操作系统和具有大容量物理内存的服务器,您应该能够将生产系统上的 _PhyRds_ 降到最低。
> 如果您在系统上看到高 _PhyRds_,可以考虑以下几种策略: - 通过增加数据库 (global) 缓冲区(和系统内存)的数量来提高性能。 - 可以将长时间运行的报告或提取移出办公时间。 - 可以在单独的影子服务器或异步镜像上运行长时间运行的只读报告、批处理作业或数据提取,以最大限度地降低对交互用户的影响,并减少对 CPU 和 IOPS 等系统资源的使用。
通常,低 _PhyRds_ 是好事情,这也是我们在确定系统规模时的目标。 然而,如果您的 _PhyRds_ 较低,而用户正在抱怨性能,仍然可以进行一些检查以确保存储不是瓶颈 - 读数低的原因可能是系统无法再提供服务。 我们将在以后的帖子中进一步探讨存储。
# 总结
在本帖中,我们研究了将 pButtons 中收集的指标图形化如何让运行状况检查可以一目了然地进行。 在接下来的帖子中,我将深入探讨系统和 Caché 指标之间的关系,以及如何利用这些指标来规划未来。
文章
Michael Lei · 五月 24, 2021
。之前我展示了如何运行 pButtons 来收集我们在下列帖子中研究的性能指标。
- [第 1 部分 - 入门:收集指标。](https://cn.community.intersystems.com/post/intersystems-数据平台和性能-–-第-1-篇)
- [第 2 部分 - 研究收集的指标。](https://cn.community.intersystems.com/post/intersystems-数据平台和性能-–-第-2篇)
## 更新:2020 年 5 月。
_自四年前写下本帖以来,我们已从 Caché 迁移到 IRIS。 有关 pButton (Caché) 和 SystemPerformance (IRIS) 文档的更新链接,请参见评论。 另请注意如何将系统更新到最新版本的性能工具。_
pButtons 与 Caché 5 及更高版本兼容,并已包含在最近的 InterSystems 数据平台分发版(HealthShare、Ensemble 和 Caché)中。 本帖旨在提醒您下载并安装最新版的 pButttons。
最新版本始终可以通过 ftp 下载。
ftp.intersystems.com/pub/performance
您需要下载以下文件:
pButtons_package.zip
解压 .zip 文件后,请查看 `readme.txt` 文件,以确保为您的 Caché 版本安装正确的文件。
要检查您现在已安装哪个版本,可以运行:
%SYS>write $$version^pButtons()
备注 1:
- 当前版本的 pButtons 需要一个许可证单元才能运行,将来的发行版将满足此要求。
- 此 pButtons 发行版的版本已更改。 — 之前的 pButtons 版本为 1.16c — 新发行版为版本 5。
备注 2:
- pButtons 版本 5 还更正了版本 1.16a 引入的一个问题,该问题可能导致收集时间非常长。 版本 1.16a 包含在 Caché 2015.1.0 中。 如果您有 pButtons 版本 1.16a 至 1.16c,则应该从 ftp 站点下载 pButtons 版本 5。
有关 pButtons 的更多详细信息,请参见下载的文件以及在线 Caché 文档。
文章
Michael Lei · 五月 24, 2021
您的应用程序已部署,一切运行正常。 很好,击个掌! 然后电话突然响个不停 – 用户投诉应用程序有时很“慢”。 这是什么意思? 有时? 您有哪些工具,查找和解决这个缓慢问题应查看哪些统计数据? 您的系统基础架构是否能承担用户负载的任务? 在投入生产之前,应该询问哪些基础架构设计问题? 如何自信地为新硬件规划容量,而不会过度规定? 如何停止电话铃声? 如何一开始就不让它响?
* * *
[本系列其他帖子的列表](https://cn.community.intersystems.com/post/intersystems-数据平台的容量规划和性能系列文章)
* * *
## 这将是一次旅程
这是本系列的第一个帖子,本系列将探讨可用于对系统性能进行监视、审查和故障排除的工具和指标,以及影响性能的系统和架构设计注意事项。 在旅程中,我们将朝多个方向前进,了解 Caché、操作系统、硬件、虚拟化以及根据评论中的反馈变为热门的其他方面的性能。
我们将关注反馈循环,其中性能数据提供了一个视角,通过它可查看已部署的应用程序和基础架构的优势和局限性,然后形成反馈以实现更好的设计和容量计划。
不言而喻,您应该不断检查性能指标,但不幸的是,如果客户只是查看数据,他们会多次对长期可见的性能问题感到惊讶。 但问题当然是 - 什么数据? 我们将从收集一些基本的 Caché 和系统指标来开始这一旅程,这样我们可以对您的系统当前的运行状况有一个感觉。 在以后的帖子中,我们将深入了解主要指标的含义。
有多个可用于系统监视的选项 – 来自 Caché 内部和外部,我们将在本系列中探讨其中的许多选项。
首先,我们将了解我最喜欢的用于连续收集数据的必备工具 ^pButtons,它已经安装在每个 Caché 系统上。
为确保您拥有最新的 pButtons 副本,请查看以下帖子:
## 收集系统性能指标 - ^pButtons
Caché 的 pButtons 实用工具可根据其创建的日志文件生成可读的 HTML 性能报告。 pButtons 输出的性能指标可以被轻松提取、绘图和审核。
pButtons html 文件中收集的数据包括:
* Caché 设置:配置、驱动器映射等。
* mgstat:Caché 性能指标 - 大多数的值是每秒平均数。
* Unix:vmstat 和 iostat:操作系统资源和性能指标。
* Windows:性能监视器:Windows 资源和性能指标。
* 其他有用的指标。
pButtons 数据收集对系统性能的影响非常小,这些指标已经由系统收集,pButtons 只是将它们打包以便归档和传输。
要保存基准以进行趋势分析和故障排除,好的做法是在一个完整的业务周期内每天收集 24 小时 pButtons(午夜到午夜)。 一个业务周期可能是一个月或更长时间,例如,从月末处理中捕获数据。 如果没有任何其他外部性能监视或收集,则可以全年运行 pButtons。
应注意以下关键点:
* 将日志目录更改为远离生产数据的位置,以存储累积的输出文件,避免出现磁盘满的问题!
* 定期运行操作系统脚本或以其他方式压缩和存档 pButtons 文件,这在 Windows 上尤其重要,因为文件可能很大。
* 定期审核数据!
如果出现需要立即分析的问题,可以预览(立即收集)pButtons 数据,同时继续存储指标,以便在当天运行结束时进行收集。
有关 pButtons 的更多信息(包括预览、停止运行和添加自定义数据收集),请参见最新的 Caché 文档中的 _Caché 监视指南_:
http://docs.intersystems.com
可以将 pButtons HTML 文件数据分离并提取(例如提取为 CSV 文件),以通过脚本或简单的剪切和粘贴将其处理成图形或进行其他分析。 我们以后将在下一个帖子中看到图表输出的例子。
当然,如果您有紧急的性能问题,请联系 WRC。
### 计划 24 小时 pButtons 数据收集
^pButtons 可以手动从终端提示符启动,也可以按计划启动。 要计划每天 24 小时收集:
1. 启动 Caché 终端,切换到 %SYS 命名空间,然后手动运行一次 pButtons 以设置 pButtons 文件结构:
%SYS>d ^pButtons Current log directory: /db/backup/benchout/pButtonsOut/ Available profiles: 1 12hours - 12 hour run sampling every 10 seconds 2 24hours - 24 hour run sampling every 10 seconds 3 30mins - 30 minute run sampling every 1 second 4 4hours - 4 hour run sampling every 5 seconds 5 8hours - 8 hour run sampling every 10 seconds 6 test - A 5 minute TEST run sampling every 30 seconds
选择选项 6 test - 5 minute TEST run sampling every 30 seconds。 请注意,您的编号可能有所不同,但 test 应该是显而易见的。
在运行期间,运行 Collect^pButtons(如下所示),您将看到包括 runid 在内的信息。 在此例中为“20160303\_1851\_test”。
%SYS>d Collect^pButtons
Current Performance runs:
<strong>20160303_1851_test</strong> ready in 6 minutes 48 seconds nothing available to collect at the moment.
%SYS>
注意到这个 5 分钟运行还剩 6 分 48 秒吗? pButtons 为所有运行增加了 2 分钟宽限期,以便有时间将日志收集和整理成 html 格式。
2. 重要!更改 pButtons 日志输出目录 – 默认的输出位置为 <缓存安装路径>/mgr 文件夹。 例如,在 unix 上,日志目录的路径可能如下所示:
do setlogdir^pButtons("/somewhere_with_lots_of_space/perflogs/")
确保 Caché 有该目录的写权限,并且有足够的磁盘空间用于累积输出文件。
3. 运行以下命令以创建一个新的 24 小时配置文件,间隔为 30 秒:
write $$addprofile^pButtons("<strong>My_24hours_30sec</strong>","24 hours 30 sec interval",30,2880)
检查该配置文件是否已添加到 pButtons:
%SYS>d ^pButtons
Current log directory: /db/backup/benchout/pButtonsOut/
Available profiles:
1 12hours - 12 hour run sampling every 10 seconds
2 24hours - 24 hour run sampling every 10 seconds
3 30mins - 30 minute run sampling every 1 second
4 4hours - 4 hour run sampling every 5 seconds
5 8hours - 8 hour run sampling every 10 seconds
6 My_24hours_30sec- 24 hours 30 sec interval
7 test - A 5 minute TEST run sampling every 30 seconds
select profile number to run:
注意:您可以更改收集间隔 – 30 秒对于例行监视是可以的。 对于例行 24 小时运行,我不会选择低于 5 秒的间隔 (…”,5,17280),因为 pButtons 在每个间隔都会收集数据,而导致输出文件变得非常大。 如果您要对一天中的某个特定时间进行故障排除,并需要更细化的数据,请使用默认的配置文件之一,或创建一个新的自定义配置文件,取较短的时间段,例如 1 小时,间隔为 5 秒 (...",5,720)。 多个 pButtons 可以同时运行,因此可以同时运行一个间隔为 5 秒的短 pButtons 和一个 24 小时 pButtons。
4. 提示 对于 UNIX 站点,可审查磁盘命令。 “iostat”命令使用的默认参数可能未包括磁盘响应时间。 首先显示当前配置了哪些磁盘命令:
%SYS>zw ^pButtons("cmds","disk")
^pButtons("cmds","disk")=2
^pButtons("cmds","disk",1)=$lb("iostat","iostat ","interval"," ","count"," > ")
^pButtons("cmds","disk",2)=$lb("sar -d","sar -d ","interval"," ","count"," > ")
要收集磁盘统计数据,请使用适合您的 UNIX 安装版的命令来编辑语法。 注意尾部空格。 以下是一些示例:
LINUX: set $li(^pButtons("cmds","disk",1),2)="iostat -xt "
AIX: set $li(^pButtons("cmds","disk",1),2)="iostat -sadD "
VxFS: set ^pButtons("cmds","disk",3)=$lb("vxstat","vxstat -g DISKGROUP -i ","interval"," -c ","count"," > ")
您可以同时运行 iostat 和 sar 命令来创建非常大的 pButtons html 文件。 对于定期的性能审查,我通常只使用 iostat。 要仅配置一个命令:
set ^pButtons("cmds","disk")=1
有关配置 pButtons 的更多详细信息,请参见在线文档。
5. 在 Management Portal > System Operation > Task Manager 中安排 pButtons 在午夜启动:
Namespace: %SYS
Task Type: RunLegacyTask
ExecuteCode: Do run^pButtons("My_24hours_30sec")
Task Priority: Normal
User: superuser
How often: Once daily at 00:00:01
### 收集 pButtons 数据
最新版的 InterSystems 数据平台中随附的 pButtons 包括自动收集功能。 要手动收集数据并整理成一个 html 文件,请在 %SYS 命名空间中运行以下命令以生成未完成的 pButtons html 输出文件:
do Collect^pButtons
该 html 文件将位于您在步骤 2 设置的日志目录中(如果您未设置,就**现在去设置!**)。 否则默认位置为 <Caché 安装目录/mgr>
文件将命名为 <主机名\_实例\_名称\_日期\_时间\_配置文件名.html>,例如 vsan-tc-db1\_H2015\_20160218\_0255_test.html
### Windows 性能监视器注意事项
如果操作系统是 Windows,则可以使用 Windows 性能监视器 (perfmon) 收集数据,与所收集的其他指标同步。 在 pButtons 的旧版 Caché 发行版中,需要手动配置 Windows perfmon。 如果帖子评论有需求,我将写一篇帖子介绍如何创建 perfmon 模板来定义要监视的性能计数器,并安排与 pButtons 相同的运行期间和间隔。
### 总结
我们从本帖开始收集一些要研究的数据。 在本周晚些时候,我将开始研究一些样本数据及其含义。 您可以使用您在自己的系统上收集的数据。 到时见。