搜索​​​​

清除过滤器
文章
Lele Yang · 二月 21, 2023

Linux Transparent HugePages 及其对 InterSystems IRIS 的影响

** 2018 年 2 月 12 日修订 虽然本文是关于 InterSystems IRIS 的,但它也适用于 Caché、Ensemble 和 HealthShare 发行版。 介绍 内存以页为单位进行管理。 Linux 系统上的默认页面大小为 4KB。 Red Hat Enterprise Linux 6、SUSE Linux Enterprise Server 11 和 Oracle Linux 6 引入了一种根据系统配置提供 2MB 或 1GB 大小的增加页面大小的方法,称为 HugePages。 起初 HugePages 需要在启动时分配,如果管理或计算不当可能会导致资源浪费。因此,各种 Linux 发行版引入了默认启用 2.6.38 内核的Transparent HugePages。这是一种自动创建、管理和使用 HugePages 的方法。以前的内核版本也可能具有此功能,但可能未标记为 [always] 而是设置为 [madvise]。 Transparent Huge Pages (THP) 是一种 Linux 内存管理系统,它通过使用更大的内存页面来减少在具有大量内存的机器上进行Translation Lookaside Buffer (TLB) 查找的开销。然而,在当前的 Linux 版本中,THP 只能映射单个进程的堆栈空间。 问题 任何 Caché 系统中的大部分内存分配都是共享内存段(全局和例程缓冲池),因为 THP 不处理这些共享内存段。因此,THP 不用于共享内存,而仅用于每个单独的进程。这可以使用一个简单的 shell 命令来确认。 以下是来自 InterSystems 的测试系统的示例,其中显示了分配给 Caché 进程的 2MB THP: # grep -e AnonHugePages /proc/*/smaps | awk '{ if($2>4) print $0} ' | awk -F "/" '{print $0; system("ps -fp " $3)} ' /proc/2945/smaps:AnonHugePages: 2048 kB UID PID PPID C STIME TTY TIME CMD root 2945 1 0 2015 ? 01:35:41 /usr/sbin/rsyslogd -n /proc/70937/smaps:AnonHugePages: 2048 kB UID PID PPID C STIME TTY TIME CMD root 70937 70897 0 Jan27 pts/0 00:01:58 /bench/EJR/ycsb161b641/bin/cache WD /proc/70938/smaps:AnonHugePages: 2048 kB UID PID PPID C STIME TTY TIME CMD root 70938 70897 0 Jan27 pts/0 00:00:00 /bench/EJR/ycsb161b641/bin/cache GC /proc/70939/smaps:AnonHugePages: 2048 kB UID PID PPID C STIME TTY TIME CMD root 70939 70897 0 Jan27 pts/0 00:00:39 /bench/EJR/ycsb161b641/bin/cache JD /proc/70939/smaps:AnonHugePages: 4096 kB UID PID PPID C STIME TTY TIME CMD root 70939 70897 0 Jan27 pts/0 00:00:39 /bench/EJR/ycsb161b641/bin/cache JD /proc/70940/smaps:AnonHugePages: 2048 kB UID PID PPID C STIME TTY TIME CMD root 70940 70897 0 Jan27 pts/0 00:00:29 /bench/EJR/ycsb161b641/bin/cache SWD 1 /proc/70941/smaps:AnonHugePages: 2048 kB UID PID PPID C STIME TTY TIME CMD root 70941 70897 0 Jan27 pts/0 00:00:29 /bench/EJR/ycsb161b641/bin/cache SWD 2 /proc/70942/smaps:AnonHugePages: 2048 kB UID PID PPID C STIME TTY TIME CMD root 70942 70897 0 Jan27 pts/0 00:00:29 /bench/EJR/ycsb161b641/bin/cache SWD 3 /proc/70943/smaps:AnonHugePages: 2048 kB UID PID PPID C STIME TTY TIME CMD root 70943 70897 0 Jan27 pts/0 00:00:33 /bench/EJR/ycsb161b641/bin/cache SWD 7 /proc/70944/smaps:AnonHugePages: 2048 kB UID PID PPID C STIME TTY TIME CMD root 70944 70897 0 Jan27 pts/0 00:00:29 /bench/EJR/ycsb161b641/bin/cache SWD 4 /proc/70945/smaps:AnonHugePages: 2048 kB UID PID PPID C STIME TTY TIME CMD root 70945 70897 0 Jan27 pts/0 00:00:30 /bench/EJR/ycsb161b641/bin/cache SWD 5 /proc/70946/smaps:AnonHugePages: 2048 kB UID PID PPID C STIME TTY TIME CMD root 70946 70897 0 Jan27 pts/0 00:00:30 /bench/EJR/ycsb161b641/bin/cache SWD 6 /proc/70947/smaps:AnonHugePages: 4096 kB 此外,运行时内存分配存在潜在的性能损失,尤其是对于具有高作业或进程创建率的应用程序。 建议 InterSystems 建议暂时禁用 THP,因为预期的性能提升不适用于 IRIS 共享内存段,并且可能会对某些应用程序产生负面性能影响。 通过运行以下命令检查您的 Linux 系统是否启用了 Transparent HugePages: 对于 Red Hat Enterprise Linux 内核: # cat /sys/kernel/mm/redhat_transparent_hugepage/enabled 对于其它内核: # cat /sys/kernel/mm/transparent_hugepage/enabled 上面的命令将显示是否启用了 [always]、[madvise] 或 [never] 标志。如果从内核中删除 THP,则 /sys/kernel/mm/redhat_transparent_hugepage 或 /sys/kernel/mm/redhat/transparent_hugepage 文件不存在。 要在引导期间禁用透明 HugePages,请执行以下步骤: 1. 将以下条目添加到 /etc/grub.conf 文件中的内核引导行: transparent_hugepage=never 2.重启操作系统 有一种方法也可以即时禁用 THP,但这可能无法提供所需的结果,因为该方法只会停止为新进程创建和使用 THP。已经创建的 THP 不会被反汇编成常规内存页。建议完全重新启动系统以在启动时禁用 THP。 *注意:建议与您各自的 Linux 经销商确认以确认用于禁用 THP 的方法。
公告
Claire Zheng · 十月 12, 2023

创意社区新闻摘要#8 | InterSystems Ideas News#8

Hi 开发者社区的成员们,大家好! 欢迎关注我们第8期 InterSystems Ideas NEWS! 本期分享如下: ​​​​✓ 描述创意门户所有页面的新视频 ✓ 自上次NEWS发布以来实施的想法 ⏯观看视频:加入名人堂 除了“创意(Idea)”页面之外,创意门户还包含 4 个新页面: 门户指南(Portal Guide) 消息(News) 民意调查(Polls) 名人堂(Hall of Fame) 欢迎查看,随时了解创意门户(Idea Portal)上的最新动态! 自创意门户(Idea Portal)推出以来,开发者社区成员已实施了24 个创意。其中 6 个是在过去 3 个月内实现的: 创意 想法的实施(项目) 开发者 Include support for GraphQL by @Jose-Tomas Salvador GraphQL @Gevorg Arutiunian REST API for Security Package by @Evgeny Shvarov Config-API @Lorenzo Scalese Jupyter Notebook by @Alex MacLeod Jupyter Server Proxy for VS Code @John Murray Java Hibernate support for IRIS by @Dmitry Maslennikov IRIS Hibernate Dialect @yurimarx Marx Example of Flask application with SQLAlchemy IRIS by @Dmitry Maslennikov IRIS-FlaskBlog @Muhammad Waseem Support for Liquibase by @yurimarx Marx liquibase-iris @Dmitry Maslennikov 👏 感谢大家实施并发布这些想法 👏 请继续关注我们的后续公告! 在我们的InterSystems 创意门户上发布您的绝妙创意,并为现有创意投票并对其发表评论!
公告
Claire Zheng · 五月 18, 2023

创意社区新闻摘要#6 | InterSystems Ideas News#6

Hi 开发者社区的成员们,大家好! 欢迎关注我们第6期 InterSystems Ideas News! 本期分享如下: ✓ 社区成员上个月实施的创意 ✓ 如何在 InterSystems Ideas 上创建新创意 ✓ 最近产生的新创意 名人堂更新了实施社区创新想法的社区成员的名字: 将 IRIS 添加为 Apache Superset 的支持数据库,该创意由@Herman Slagman 提出,由 @Dmitry Maslennikov 实施 请添加 google oauth 授权以登录管理门户,该创意由 @Aleksandr Kolesov 提出,由 @Yuri Marx 实施 👏感谢您实践这些创意👏 新文章“ 如何在 InterSystems Ideas 上创建新创意”逐步描述了创意创建的过程。在向门户添加新想法时阅读它。 为了总结本期时事通讯,以下是自上次新闻公告以来发布的新想法列表 1. @Evgeny Shvarov : 转储 SQL 表2. @Dmitry Maslennikov :对 IRIS 的 Java Hibernate 支持3. @Evgeny Shvarov :为 ObjectScript 变量名添加合法的特殊符号分隔符 4.@Robert Cemper :允许取消“待批准” 5.@Robert Cemper :提供隐藏/取消隐藏帖子的开关。或修复重新发布6. @Scott Roth :Java 网关跟踪路由显示7.@John Murray :在开发者社区将动画 GIF 放在播放/暂停按钮后面8. @yurimarx Marx :在 GEO 仪表板上的数字社区9.@Robert Barbiaux :在 VSCode 中进行单元测试10. @Scott Roth :在消息搜索中保存搜索条件11. @yurimarx Marx :特色文章或问题 👏感谢您发布新想法👏 请继续关注下一期 InterSystems Ideas 新闻公告! 保持创意,在InterSystems Ideas上发布您的奇思妙想,对现有想法进行投票和评论!
文章
Louis Lu · 四月 15, 2021

第 4 天:使用 InterSystems Objects 和 SQL 进行开发

我正在参加 Joel Solon 讲授的“使用 InterSystems Objects 和 SQL 进行开发”课程。 课程非常好,我将在这里分享一些从培训中总结的提示。 第 4 天的提示: 1. 所有数据都存储在global中,global名称以 ^ 开头。 global示例:^animal。 global可以有多个数据位置(“子数据”)。 示例:^animal("大象","吃草")。 2. 可从任意系统范围(命名空间)访问 ^%* global。 3. global使 IRIS 能够支持多模型数据(对象、关系、文档、多维等)。 4. 要查看global,请转到 Management Portal > Explorer > Globals > Select Global > View,或者在终端中输入 do ^%G 或 zwrite ^global。 5. 在持久类和 SQL 表之间有自动对应关系: 包对应于是 SQL Schema; 类是Table; 属性是列; 方法是存储过程(使用 sqlProc 时); 类之间的关系是 SQL 外键约束(必须为双向)。 对象是行。 6. 一个表可以对应多个类,但序列类serial是持久类表的一部分(没有特定的表)。 7. 一个类可以对应多个表。 8. 我们有一些类类型: Non-registered:不是类对象(仅限方法的容器); Registered:瞬态对象; Persistent:类似于SQL表中持久化保存; Serial:嵌入主持久化表中的持久表(Serial为嵌入式); Datatype:非类对象用于执行新的验证和转换为基础数据类型。 9. 类的组成可包括: 属性; 方法; Class queries:SQL Select 语句; Parameters:配置类行为的用户常量或系统常量; 外键:参照完整性; 索引:提高性能并创建独特值; 触发器:触发与持久性事件关联的方法; XData:与该类关联的 XML 或 JSON 定义; 存储:数据存储的描述。 10. 按照惯例,类的首字母大写。 示例:CountryOrigin。 参数均为大写。 示例:COLORNUMBER。 11. 类特性限定/配置一个类。 示例 [SqlTableName = Animal] 可设置SQL表名。 [Final] 不允许继承。 [Private] 不允许为非子类调用方法或使用属性。 12. IRIS 在内部生成 Get 和 Set 属性,这些属性不可见,但可以通过声明改变行为。 13. 可以重写超类的方法,为此,请重复类名、参数。 可以增加参数的数量,不可减少。 14. 使用 ##super() 调用基类方法。 15. 要创建抽象类,请使用 [Abstract] 并防止实例化。 16. 可以继承多个类。 例如,Class Person extends (%Persistent, %Animal)。 (Persistent 必须是 extends 中的第一个类,参见评论中 joel 的提示) 17. REST 是表述性状态转移。 它基于 HTTP 协议。 使用 HTTP 谓词:GET(选择)、POST(插入)、PUT(更新)和 DELETE(删除)。 18. 要将您的类作为 REST 资源公开,请从 %CSP.REST 扩展。 19. 在 XData 块中使用 URLMap 配置 REST 服务的路由。 使用门户,创建一个 Web 应用程序,启用 REST 并指定 Dispatch 类。 20. %JSONAdaptor 提供了对象与 JSON 之间的转换。 使用 obj.%JSONImport(jsonObj) 将 DynamicObject 分配到对象。 使用 obj.%JSONExportToString(.jsonString) 将 JSON 字符串写入对象。 21. %JSON.Formatter 格式化 JSON 字符串以便人类阅读。
文章
Louis Lu · 四月 15, 2021

第 2 天:使用 InterSystems Objects 和 SQL 进行开发

原文在这里 原作者YURI MARX GOMES 我正在参加 Joel Solon 讲授的“使用 InterSystems Objects 和 SQL 进行开发”课程。 课程非常好,我将在这里分享一些从培训中总结的提示。 第 2 天的提示: 1. 您可以创建持久类(在数据库中具有对应表的类,用于保持类属性)。 2. 持久类示例: Class dc.Person extends (%Persistent) { Property Name As %String; Property BirthDate As %Date; } 3. 扩展 %Persistent 时,您将获得 %New() 以在内存中创建新实例,获得 %Save() 以保存到数据库,获得 %Id() 以获取该实例在数据库中的唯一 ID,以及获得 %OpenId() 以使用数据库值加载实例。 4. 持久类允许您调用 %Deleteid() 以从数据库中删除一个实例,调用 %DeleteExtent() 以删除所有保存的对象(没有 where 时删除!),调用 %ValidateObject() 以验证保存前传递的数据(验证是否必需、大小等)。 5. 持久类具有 %IsModified() 和 %Reload(),前者用于检查内存中的数据变化(参见评论中 joel 的提示),后者用于获取这些变化。 6. 要在尝试 %Save() 或 %Delete() 时获得可能的错误,请执行:set status = person.%Save(), write status。 如果保存成功,将返回 1。 7. 我们可以使用 do $system.Status.DisplayError(status) 查看错误详细信息。 8. 要调用持久类方法,请执行:##class(dc.Person).%Save()。 9. 要调用持久实例方法,执行:..Method()。 引用属性也一样,请执行:write ..Name。 10. 要从程序或终端内存中移除对象或变量,请使用 kill person 或 set person = ""。 如果仅使用 kill,将从内存中移除所有引用(不是从数据库中移除,在数据库中使用 killextent)。 11. 如果要通过实用工具方法填充测试数据,请使用 %Populate 扩展持久类,然后调用 Populate(行数)方法。 12. 您可以通过继承%SerialObject(不具有 ID 的持久类,因为它必须与另一个持久类相连)创建嵌入式类。 示例: Class dc.Contact Extends %SerialObject { Property Phone As %String; Property Email As %String; } 13. 此序列将成为您的持久类的一个属性: Class dc.Person extends (%Persistent) { Property Name As %String; Property BirthDate As %Date; Property Contact As dc.Contact; } 14. 在 IRIS 数据库中,将仅创建一个具有 Contact 属性的Person表。 15. 您可以创建索引来获得唯一性或调整查询。 示例:Index NameIndex On Name [Unique]。 16. 创建索引时,如果表不为空,则需要在管理门户中重建索引。 17. 要创建构造函数方法,请重写 %OnNew()。 这是在调用 %New() 时调用的回调方法。 还有其他回调方法。 18. IRIS 对 JSON 有很好的支持。 您可以通过调用 set name = {}.%FromJSON("{""Name"":""Yuri""}") 将 JSON 加载到对象。 19. 您可以从对象执行编写 JSON:name.%ToJSON()。 20. IRIS 和 Caché 中存在 JSON 数组(感谢 @Robertcc.Cemper 提醒),但是只在 IRIS 中我们才有 JSON 的格式化程序和zwrite 写入 JSON。 明天我会发布第 3 天的总结。 PS:这是一份总结,课程中实际教授了更多内容。
公告
Claire Zheng · 七月 10, 2023

InterSystems 2023年度编程大奖赛获奖名单出炉!

Hi 开发者们, 是时候宣布InterSystems 2023 年度编程大奖赛的获奖者了! 感谢提交20 份应用申请出色参与者们 🔥 专家提名奖 🥇第一名,7,000 美元,获奖者@Henrique Dias, @Henry Pereira, @José Roberto Pereira ,获奖应用 iris-fhir-generative-ai 🥈第二名,5,000 美元,获奖者@Ikram Shah, @Sowmiya Nagarajan,获奖应用 IRIS FHIR Transcribe Summarize Export 🥉第三名,3,000 美元,获奖者 @Muhammad Waseem 获奖应用irisChatGPT 🏅第四名,2,000 美元,获奖者@Dmitry Maslennikov,获奖应用ZProfile 🏅第五名 ,1,000 美元,获奖者@Ikram Shah, @Sowmiya Nagarajan ,获奖应用 FHIR - AI and OpenAPI Chain 🌟 200 美元,获奖者:@Robert Cemper, 获奖应用oex-mapping 🌟 200 美元,获奖者:@Rob Ellis, 获奖应用RDUH Interface Analyst HL7v2 Browser Extension 🌟 200 美元,获奖者:@davi massaru teixeira muta, 获奖应用fhir-chatGPT 🌟 200 美元,获奖者:@davi massaru teixeira muta, 获奖应用interoperability_GPT 🌟 200 美元,获奖者:@Oleksandr Zaitsev ,获奖应用password-app-iris-db 🌟 200 美元,获奖者:@Daniel Aguilar 获奖应用irisapitester ⭐️ 100 美元,获奖者:@Shanshan Yu,获奖应用IntegratedMLandDashboardSample ⭐️ 100 美元,获奖者:@Zhang Fatong 获奖应用 IntegratedML-IRIS-PlatformEntryPrediction ⭐️ 100 美元,获奖者:@Sean Connelly 获奖应用DevBox ⭐️ 100 美元,获奖者:@John Murray 获奖应用 oex-vscode-snippets-template ⭐️ 100 美元,获奖者:@Sergey Mikhailenko,获奖应用appmsw-warm-home ⭐️ 100 美元,获奖者:@yurimarx Marx, 获奖应用 FHIR Editor ⭐️ 100 美元,获奖者:@Oliver Wilms,获奖应用iris-user-manager ⭐️ 100 美元,获奖者:@Oleh Dontsov 获奖应用 Recycler ⭐️ 100 美元,获奖者:@Oleh Dontsov 获奖应用 IRIS Data Migration Manager 社区提名奖 🥇第一名,3,000 美元,获奖者@Henrique Dias, @Henry Pereira, @José Roberto Pereira ,获奖应用 iris-fhir-generative-ai 🥈第二名,2,000 美元,获奖者@Shanshan Yu,获奖应用IntegratedMLandDashboardSample 🥉第三名,1,000 美元,获奖者@Zhang Fatong,获奖应用 IntegratedML-IRIS-PlatformEntryPrediction 我们向所有参赛者和获奖者表示最诚挚的祝贺! 下次一起来参赛吧!;) 热烈祝贺 @Shanshan Yu@Zhang Fatong二位中国选手!期待以后看到更多的优秀作品!
公告
Claire Zheng · 九月 3, 2024

InterSystems开发者社区中文版:中文社区最佳贡献奖公布(2024年8月)

Hi 开发者们, 2024年8月,我们继续💡“中文社区最佳贡献奖”💡活动,截至目前,社区共有成员1900余人,8月新增成员30人。 🎉🎉🎉🎉获奖名单公布🎊🎊🎊🎊 在综合考虑了发帖量、评论等社区贡献后,我们宣布8月“中文社区最佳贡献奖”获得者为: 👍现有成员 @HoneyMoose 👍现有成员 @Xiang.Zhang 🍀恭喜两位,我们将寄出奖品:《AI医疗革命》。 为感谢大家的积极参与,鼓励更多社区成员积极贡献到社区建设中,我们将为以下社区新成员送上奖励: 🆕新增成员 @PGUO 🆕新增成员 @于涵.邱 🍀恭喜以上获奖成员,我们将寄出奖品:InterSystems开发者社区定制礼品一份🍀 🏆领奖须知🏆 请以上获奖成员及时通过站内信与 @Yunfei.Lei 沟通奖品领取事宜(截至2024年9月20日)。 🍀如果您对此次活动有任何疑问,欢迎跟帖提问!🍀
文章
姚 鑫 · 二月 25, 2021

第四十七章 Caché 变量大全 ^$JOB 变量

# 第四十七章 Caché 变量大全 ^$JOB 变量 提供系统间IRIS进程(`JOB`)信息。 # 大纲 ```java ^$JOB(job_number) ^$J(job_number) ``` # 参数 - `job_number` 输入ObjectScript命令时创建的系统特定OBJ编号。每个活动的InterSystems IRIS进程都有一个唯一的作业号。登录到系统会启动一个作业。在UNIX®系统上,作业号是调用InterSystems IRIS时启动的子进程的`PID`。`JOB_NUMBER`必须指定为整数;不支持十六进制值。 # 描述 可以将`^$JO`B结构化系统变量用作`$DATA`、`$ORDER`和`$QUERY`函数的参数,以获取有关本地InterSystems IRIS系统上是否存在InterSystems IRIS作业的信息。 # 示例 以下示例显示如何将`^$JOB`用作`$DATA`、`$ORDER`和`$QUERY`函数的参数。 ## 作为$DATA的参数 `$DATA(^$JOB(job_number))` `^$JOB`作为`$DATA`的参数返回一个整数值,该值指示指定的作业是否作为节点存在于`^$JOB`中。下表显示了`$DATA`可以返回的整数值。 Value | Meaning ---|--- 0 | `JOB`不存在 1 | `JOB`存在 以下示例测试系统间IRIS进程是否存在。 ```java DHC-APP>SET x=$JOB DHC-APP>WRITE !,$DATA(^$JOB(x)) 1 ``` 变量`x`设置为当前进程的作业号(例如:4294219937)。写入操作返回布尔值1,表示此进程存在。 ## 作为$ORDER的参数 `$ORDER(^$JOB(job_number),direction)` `^$JOB`作为`$ORDER`的参数,按排序顺序将下一个或上一个`^$JOB`编号返回到指定的作业编号。如果不存在作为`^$JOB`节点的此类`JOB`编号,`$ORDER`将返回空字符串。 Direction参数指定是否返回下一个或上一个`job`编号。如果不提供方向参数,InterSystems IRIS会将排序顺序中的下一个`job`编号返回给指定的`job`编号。 以下子例程搜索InterSystems IRIS作业表,并将`job`号存储在名为`job`的本地数组中。 ```java /// d ##class(PHA.TEST.SpecialVariables).JOB() ClassMethod JOB() { JOB SET pid="" FOR i=1:1 { SET pid=$ORDER(^$JOB(pid)) QUIT:pid="" SET JOB(i)=pid } zw JOB WRITE "总共job有: ",i QUIT } ``` ```java DHC-APP>d ##class(PHA.TEST.SpecialVariables).JOB() JOB(1)=612 JOB(2)=1424 JOB(3)=1972 JOB(4)=5624 JOB(5)=7244 JOB(6)=7864 JOB(7)=7872 JOB(8)=7892 JOB(9)=7920 JOB(10)=8332 JOB(11)=9048 JOB(12)=9084 JOB(13)=9340 JOB(14)=10084 JOB(15)=10112 JOB(16)=10156 JOB(17)=10200 JOB(18)=10212 JOB(19)=10828 JOB(20)=22432 总共job有: 21 ``` ## 作为$QUERY的参数 `$QUERY(^$JOB(job_number))` `^$JOB`作为`$QUERY`的参数,按排序顺序将下一个`^$JOB`编号返回到指定的`JOB`编号。如果`^$JOB`中没有这样的`JOB`编号作为节点,则`$QUERY`将返回空字符串。 以下示例返回InterSystems IRISJOB表中的前两个`JOB`。请注意间接运算符`(@)`的用法: ```java DHC-APP>SET x=$QUERY(^$JOB("")) DHC-APP> WRITE !,x ^$JOB("612") DHC-APP>WRITE !,$QUERY(@x) ^$JOB("1424") ```
公告
Claire Zheng · 八月 7, 2024

InterSystems开发者社区中文版:中文社区最佳贡献奖公布(2024年7月)

Hi 开发者们, 2024年7月,我们开启了💡“中文社区最佳贡献奖”💡活动,截至目前,社区共有成员1900余人,7月新增成员46人。 🎉🎉🎉🎉获奖名单公布🎊🎊🎊🎊 在综合考虑了发帖量、评论等社区贡献后,我们宣布7月“中文社区最佳贡献奖”获得者为: 🆕新增成员 @y.g 👍现有会员 @姚.鑫 恭喜两位,我们将寄出奖品:《AI医疗革命》。 为感谢大家的积极参与,鼓励更多社区成员积极贡献到社区建设中,我们还将为以下成员送上奖励: 🆕新增成员 @zhangchao @biubiu.biubiu 👍现有成员 @deng.hang @liu.bo 🍀恭喜以上获奖成员,我们将寄出奖品:InterSystems开发者社区定制礼品一份🍀 🏆领奖须知🏆 请以上获奖成员及时通过站内信与 @Xuying.Zheng 沟通奖品领取事宜(截至2024年9月20 日)。 ⏭接下来 我们的活动还在继续,将于9月初公布8月获奖名单! 🍀如果您对此次活动有任何疑问,欢迎跟帖提问!🍀
文章
Louis Lu · 四月 15, 2021

第 3 天:使用 InterSystems Objects 和 SQL 进行开发

我正在参加 Joel Solon 讲授的“使用 InterSystems Objects 和 SQL 进行开发”课程。 课程非常好,我将在这里分享一些从培训中总结的提示。 第 3 天的提示: 1. 您可以使用 %Dictionary 类查看类目录,并在 INFORMATION_SCHEMA 表中查看 sql 对象。 2. 可以在 ObjectScript 方法中以动态 SQL 或嵌入式 SQL 使用 SQL。 3. 您可以使用 ?(例如:where country = ?)将参数传递到动态 SQL 字符串, 使用冒号(例如:where country = :variable)将参数传递到嵌入式 SQL。 4. 动态 SQL 示例(来自 Intersystems 文档): SET tStatement = ##class(%SQL.Statement).%New(,"Sample") SET myquery = 3 SET myquery(1) = "SELECT TOP ? Name,DOB,Home_State" SET myquery(2) = "FROM Person" SET myquery(3) = "WHERE Age > 60 AND Age < 65" SET qStatus = tStatement.%Prepare(.myquery) IF qStatus'=1 {WRITE "%Prepare failed:" DO $System.Status.DisplayError(qStatus) QUIT} DO tStatement.%Display() WRITE !,"End of %Prepare display" 5. 嵌入式 SQL 示例(来自 Intersystems 文档): #SQLCompile Select=Display &sql(SELECT DOB INTO :a FROM Sample.Person) IF SQLCODE<0 {WRITE "SQLCODE error ",SQLCODE," ",%msg QUIT} ELSEIF SQLCODE=100 {WRITE "Query returns no results" QUIT} WRITE "1st date of birth is ",a,! DO $SYSTEM.SQL.Util.SetOption("SelectMode",1) WRITE "changed select mode to: ",$SYSTEM.SQL.Util.GetOption("SelectMode"),! &sql(SELECT DOB INTO :b FROM Sample.Person) WRITE "2nd date of birth is ",b 6. 嵌入式 SQL 示例 - 插入: &sql(INSERT INTO Sample.Person (Name, Age, Phone) VALUES (:name, :age, :phone) 7. 如果您需要使用 SQL 批量处理数据,处理单个记录,请使用 Persistent Object API。 8. 您可以创建 SQLQuery 方法,如果在方法中使用 [SqlProc],将在 SQL 端中创建一个 SQL 存储过程。 9. 从终端可以进入 SQL Shell,要从终端进入 SQL 命令,请执行 do $system.SQL.Shell()。 10. 持久类具有系统生成的 ID,如果需要由您控制的 ID,您可以使用具有一个或多个属性的 IDKEY 索引。 例如,SocialNumber [IdKey, PrimaryKey, Unique] 上的索引键。 11. 当两个或多个进程同时尝试处理相同数据时,有两种控制并发的策略:悲观型和乐观型。 12. 要获取悲观控制,请使用 %OpenId(ID, 4) 锁定对象,其中 4 会将表锁定为互斥访问。 在进程运行后,可以释放锁定。 13. 要进行乐观控制(针对 Web 应用),在您的持久类中创建 Parameter VERSIONPROPERTY = "Version"; Property Version as %Integer [ InitialExpression = 1 ]。 IRIS 会在每次实例更新时递增属性版本,这样可以协调更新顺序,而不是锁定表。 14. 当您有更新、插入或删除数据的方法时,请使用事务保持数据一致。 示例: Transfer(from,to,amount) // Transfer funds from one account to another { TSTART &SQL(UPDATE A.Account SET A.Account.Balance = A.Account.Balance - :amount WHERE A.Account.AccountNum = :from) If SQLCODE TRollBack Quit "Cannot withdraw, SQLCODE = "_SQLCODE &SQL(UPDATE A.Account SET A.Account.Balance = A.Account.Balance + :amount WHERE A.Account.AccountNum = :to) If SQLCODE TROLLBACK QUIT "Cannot deposit, SQLCODE = "_SQLCODE TCOMMIT QUIT "Transfer succeeded" } 15. InterSystems IRIS 的架构基于命名空间(数据库的逻辑组)和数据库。 16. 要在数据库中保存的数据有两种类型:数据(global)和代码(源代码 - 过程)。 17. 您可以使用 ECP(企业缓存协议)对数据库进行水平处理扩展,这样可以在同一命名空间访问查看多个服务器中不同的数据库。 18. 您可以使用Sharding(仅限 IRIS)进行水平数据量扩展(分布式数据库分区),这样可以将数据分区到分布式节点(如 MongoDB)。 19. 数据库的最大容量是 32TB。 20. 要从一个命名空间更改为另一个命名空间,请执行 zn "Namespace" 或 set $namespace = "Namespace"。 PS 1:课程详细展示了如何进行事务控制,这非常重要。 明天我会发布第 4 天的总结。
文章
姚 鑫 · 八月 29, 2022

第十六章 维护本地数据库(一)

# 第十六章 维护本地数据库(一) 可以在管理`Portal` (`System Operations` > `databases`)的“数据库”页面查看和维护本地数据库。 在此页面,可以查看到以下信息: - 数据库一般信息` Databases General Information`-所有数据库的概述信息。 - 数据库空闲空间信息 `Databases Free Space Information` - 所有数据库的空闲空间信息 - 数据库详细信息页 `Database Details Page` -个别数据库的特定信息。 还可以通过维护操作增加该页面的可用空间。 本节中描述的大多数信息和操作也可以使用`^DATABASE`命令行实用程序找到并执行。 # 数据库的一般信息 数据库页面(系统操作 > 数据库)包含所有本地数据库的列表。对于每个本地数据库,会看到以下信息: #### 本地数据库信息 - `Name` - 数据库名称。 - `Directory` - 分配给数据库可以增长的最大大小,以 `GB` 为单位。 - `Max Size (GB)` - 分配给数据库可以增长的最大大小,以 `GB` 为单位。 - `Size (MB)` - 当前分配的数据库大小,以兆字节为单位。 注意:此字段衡量数据库的逻辑大小。因此,此处报告的大小可能低于数据库的物理大小,特别是对于 `IRISTEM` 数据库。 - `Status` - 数据库的状态:`mounted` (包括它有哪些权限)、`unmounted`或`dismounted`。 - 已安装的数据库是选择了启动时需要安装的数据库,因此必须安装该数据库才能使 `IRIS` 启动或成为镜像中的主数据库;在这种情况下,它总是在 `IRIS` 启动时被安装和访问。或者,它是一个先前未挂载的数据库,在访问它或显式挂载时已动态挂载;在这种情况下,它会一直挂载,直到明确卸载它或重新启动/停止 `IRIS`。 - 未挂载的数据库是未选择启动时需要挂载的数据库,因此不需要挂载 `IRIS` 即可启动或成为镜像主数据库,并且既未访问也未显式挂载;当访问它或显式安装它时,它会动态安装,并保持安装状态,直到显式卸载它或重新启动/停止 `IRIS`。 - 已卸载的数据库是已显式卸载的数据库;在显式安装它或重新启动/停止 `IRIS` 之前,它是不可访问的(也就是说,如果尝试访问已卸载的数据库,则不会动态安装它)。要永久卸载数据库,您必须将其从配置中删除。 - `Encrypted` - 指示数据库是否已加密。 - `Journal` - 指示数据库中的全局变量是用 `Y` 还是 `N` 记录的。 此外,该页面包含一个过滤栏,可以使用它来控制显示的数据库数量。例如,要仅列出系统数据库,可以在 `Filter:` 文本框中输入 `IRIS*`;和/或要每页仅列出五个数据库,请在页面大小:文本框中输入 `5`;和/或将显示的行数限制为 `3`,在 `Max rows`: 文本框中输入 `3`(在 `Results` 字段中显示带有数字的 `+` 号表示存在满足指定条件的其他数据库,但它们不会显示)。 # 数据库可用空间信息 管理数据库中的可用空间(空块)是数据库维护的一个重要方面。要查看可用空间信息,可以显示管理门户的可用空间视图或使用 `^%FREECNT` 实用程序。请记住,正常操作中数据库的大小和可用空间属性会不断变化,门户网站或实用程序在给定时间点报告的数字只是近似值。 ## 使用管理门户显示可用空间信息 要显示可用空间信息,其中显示有关每个本地数据库上可用空间量的信息,请导航到数据库页面(系统操作 > 数据库)并单击可用空间视图单选按钮。下表描述了显示的信息: #### 本地数据库可用空间信息 - `Name` - 数据库名称。 - `Directory` - 数据库的主卷所在的系统目录。 - `Max Size` - 数据库可以增长到的最大分配大小,以 `GB` 为单位。创建数据库时默认为无限制。 - `Size` - 当前分配的数据库大小,以兆字节为单位。 注意:此字段衡量数据库的逻辑大小。因此,此处报告的大小可能低于数据库的物理大小,特别是对于 `IRISTEM` 数据库。 - `Expansion Size` - 扩展数据库的大小(以 `MB` 为单位)。创建数据库时,默认和推荐设置为零 (`0`),这表示使用系统默认值(当前大小的 `12%` 或 `10 MB`,以较大者为准)。在此设置下,扩展大小不会大于 1GB。 - `Available` - 数据库中可用的可用空间量(以 `MB` 为单位)。 - `%Free` - 数据库中可用空间的百分比。 - `Disk Free Space` - 卷上的可用空间量。 - `Status` - 目录的状态,指示数据库是否已挂载以及具有哪些权限。 # 使用 ^%FREECNT 显示可用空间信息 `IRIS` 还提供了 `^%FREECNT` 实用程序,可以通过在终端中输入 `do` `^%FREECNT` 来运行该实用程序,以显示数据库中的可用空间。 在 `%SYS` 命名空间中使用 `^%FREECNT` 时,可以选择通过在提示符处输入星号 (`*`) 来显示所有数据库的可用空间,或者输入一个数据库目录名称。例如: ```java %SYS>do ^%FREECNT Database directory to show free space for (*=All)? * Databases Selected ------------------ c:\intersystems\irishealth\mgr\ c:\intersystems\irishealth\mgr\enslib\ c:\intersystems\irishealth\mgr\hscustom\ c:\intersystems\irishealth\mgr\hslib\ c:\intersystems\irishealth\mgr\hssys\ c:\intersystems\irishealth\mgr\irisaudit\ c:\intersystems\irishealth\mgr\irislib\ c:\intersystems\irishealth\mgr\irislocaldata\ c:\intersystems\irishealth\mgr\iristemp\ c:\intersystems\irishealth\mgr\user\ Device: Right margin: 80 => Database Free Space Aug 20 2022 12:30 PM Database Max Size Size Available %Free Disk Free c:\intersystems\irishealth\mgr\ 无限制 113MB 19MB 16.81 31.67GB c:\intersystems\irishealth\mgr\enslib\ 无限制 208MB 16MB 7.69 31.67GB c:\intersystems\irishealth\mgr\hscustom\ 无限制 21MB 8.7MB 41.42 31.67GB c:\intersystems\irishealth\mgr\hslib\ 无限制 1.19GB 132MB 10.82 31.67GB c:\intersystems\irishealth\mgr\hssys\ 无限制 21MB 8.9MB 42.38 31.67GB c:\intersystems\irishealth\mgr\irisaudit\ 无限制 11MB 10.0MB 90.9 31.67GB c:\intersystems\irishealth\mgr\irislib\ 无限制 356MB 0.51MB .14 zn "user" USER>do ^%FREECNT Databases Selected ------------------ c:\intersystems\cache\mgr\user\ Device: Right margin: 80 => Cache Database Free Space Aug 20 2022 12:32 PM Database Max Size Size Available %Free Disk Free c:\intersystems\cache\mgr\user\ 无限制 11MB 9.4MB 85.45 31.67G B ``` **注意:`
文章
Claire Zheng · 一月 20, 2021

使用内置的REST API监控InterSystems IRIS

我们不必等待SAM发布才开始规划和试用该API来监控IRIS实例。在以后的文章中,我将更深入地探讨可用的指标及其意义,并提供一些交互式仪表板的示例。首先,我将介绍一下相关背景和一些问题及答案。 IRIS(和Caché)一直在收集自身及其运行平台的数十个指标。收集这些指标来监控Caché和IRIS的方法向来有很多。我发现,很少有安装软件使用IRIS和Caché的内置解决方案。譬如,History Monitor作为性能和系统使用指标的历史数据库,已经推出很长时间了,但它没有简便方法可实时显示这些指标和仪表系统。 IRIS平台解决方案(以及整个业界)正在从仅在一些本地实例上运行的单体式应用程序过渡到“随处”部署的分布式解决方案。在许多用例中,原有的IRIS监控方案并不适用于这些新的模式。InterSystems没有做重复工作,而是将目光投向当前流行的、经过验证的监控和告警开源解决方案。 Prometheus? Prometheus是一个基于成熟技术、应用广泛的著名开源监控系统,具有多种多样的插件。Prometheus的设计目的是在云环境中很好地运行,但它同样适用于本地环境。Prometheus的插件包括操作系统、web服务器(如Apache)和许多其他的应用程序。Prometheus通常与前端客户端(如Grafana)一起使用,后者可提供极具定制性的一流UI/UX体验。 Grafana? Grafana也是开源平台。随着本系列文章的深入,我将提供常见场景监控仪表板的示例模板。在这些示例模板的基础上,你可以进一步设计自己想要的各种仪表板。将IRIS指标与你的整个解决方案堆栈的各项指标适当结合,就可以发挥真正的威力;各项指标来自于平台组件、操作系统、IRIS,尤其是当你在应用程序中添加仪表功能的时候。 我以前见过这种方法吗? 使用Prometheus和Grafana监控IRIS与Caché并不是新出现的方法。几年来,我一直使用这些应用程序监控我的开发和测试系统。在开发者社区中搜索“Prometheus”,就可以找到一些其它文章,这些文章讲述了如何显示Caché指标,以供Prometheus使用。 跟过去不同的是,现在的/api/monitor API是内置的,而且默认启用。用户无需为显示指标而自己编写类。 Prometheus入门 在这里简单介绍一下Prometheus和一些术语。希望读者能够深入学习并打下一定基础,这将有助于你思考如何运用IRIS或其他来源提供的各项指标或将其可视化。 Prometheus的工作方式是抓取或提取由作为HTTP端点的应用程序(IRIS /api/monitor等API)所公开的时间序列数据。现有的导出器和客户端库适用于多种语言、框架、开源应用程序(例如Apache等web服务器)、操作系统、docker、Kubernetes、数据库和现在的IRIS。 导出器用于将应用程序和服务仪表化,并公开端点上的相关指标以进行抓取。核心导出器支持各种标准组件,例如web服务器、数据库等。其他多种开源导出器可从Prometheus社区获取。 Prometheus术语 有几个关键术语需要了解: ·目标 是指你关心的服务所处的位置,例如主机、应用程序或服务(如:Apache、IRIS或你自己的应用程序)。 ·Prometheus 通过HTTP抓取目标,以收集指标作为时间序列数据。 ·时间序列数据 是通过应用程序(如IRIS)或导出器公开的。 ·导出器 可用于你无法控制的数据,譬如Linux内核指标。 ·生成的时间序列数据 存储在本地Prometheus服务器上的一个数据库中**。 ·这个时间序列数据库 可以使用优化的查询语言(PromQL)进行查询,以便创建警报或者由客户端应用程序(如Grafana)在仪表板中显示指标等。 **剧透警告:出于安全性、扩展性、高可用性及运营效率方面的考虑,在新的SAM解决方案中,Prometheus时间序列数据所使用的数据库是IRIS数据库!但对IRIS平台的Prometheus数据库的访问是透明的,而应用程序(如Grafana)对这些访问既不知道也不关心。 Prometheus数据模型 该API返回的指标是Prometheus格式的。Prometheus采用基于文本的简单指标格式,每行一个指标,格式如下: [ (timen, valuen), ....] 指标可将标签作为(键,值)对,而标签是将指标作为维度过滤的强大方法。例如,检验IRIS /api/monitor返回的一个指标──日志可存储空间: iris_jrn_free_space{id="WIJ",dir=”/fast/wij/"} 401562.83 标识符反映了指标的含义和来源: iris_jrn_free_space 多个标签可用于修饰指标,然后用来过滤和查询。在这个例子中,可以看到WIJ及其存储目录: id="WIJ",dir="/fast/wij/" 此外,还有一个值:401562.83(MB)。 有哪些IRIS指标可供使用? 预览版文档资料中含有一个指标列表。但要注意,其中的内容可能会有所调整。你也可以查询/api/monitor/metrics端点以查看列表。我使用的是Postman,关于这一点,我将在下一篇文章中进行阐述。 我应该监控什么? 考虑怎样监控你的系统和应用程序时,请记住以下要点: 1. 尽可能将影响用户的关键指标仪表化 o用户并不关心你的某台机器是否缺少CPU。 o用户关心的服务是否缓慢或出错。 o你的主仪表板应显示那些直接影响用户的高级指标。 2. 仪表板应避免显示大量图表 o人无法一次性处理太多数据。 o例如:每项服务都有一个仪表板。 3. 关注服务,而不是机器 o将问题定位到某项服务之后,你就可以接着往下找原因,看看是否是哪台机器出了问题。 参考资料 文档资料和下载 Prometheus:https://prometheus.io/ Grafana:https://grafana.com/ 在InterSystems 2019年全球峰会上,我简要介绍了预发布版SAM(包括Prometheus和Grafana);你可以在InterSystems学习服务网站上找到相关链接。如果此链接无效,请访问InterSystems学习服务网站,并搜索:“System Alerting and Monitoring Made Easy”。 你也可以在社区中搜索“Prometheus”和“Grafana”。 注:本文为译文,欢迎点击阅读原文,原文由Murray Oldfield撰写
文章
Qiao Peng · 二月 6, 2021

InterSystems:技术支持和 DBMS 互操作性管理解决方案

在本文中,我们将讨论一个我每天都会使用的应用程序,当监控 InterSystems IRIS 平台上的应用程序和集成解决方案并查找所发生的错误时,我就会用到它。 在查找用来记录 InterSystems IRIS、Ensemble 和 Caché DBMS 中对象变化的解决方案时,我发现了一篇关于[使用宏进行日志记录](https://community.intersystems.com/post/logging-using-macros-intersystems-cach%C3%A9)的好文章。 受到该文章的启发,我对其介绍的项目进行了分叉,并做了相应调整以满足一些特定需求。 生成的解决方案以面板子类 %CSP.Util.Pane 的形式实现,它具有主命令窗口、“Run”(运行)按钮和已启用的命令配置。 该应用程序允许查看和编辑 global 数组、执行查询(包括 JDBC 和 ODBC)、通过电子邮件发送搜索结果(压缩的 XLS 文件)、查看和编辑对象,以及用几个简单图表来表示系统协议。 该 apptools-admin 应用程序基于 jQuery-UI、UiKit、chart.js 和 jsgrid.js。 欢迎查看[源代码](https://openexchange.intersystems.com/package/apptools-admin)。 ### 安装 仓库中详细介绍了所有安装方法。 但是,最简单的方法是使用包管理器命令: ``` zpm "install apptools-admin" [apptools-admin] Reload START [apptools-admin] Reload SUCCESS [apptools-admin] Module object refreshed. [apptools-admin] Validate START [apptools-admin] Validate SUCCESS [apptools-admin] Compile START [apptools-admin] Compile SUCCESS [apptools-admin] Activate START [apptools-admin] Configure START http://hp-msw:52773/apptools/apptools.core.LogInfo.cls http://hp-msw:52773/apptools/apptools.Tabs.PanelUikitPermissMatrx.cls?autoload=Matrix [apptools-admin] Configure SUCCESS [apptools-admin] Activate SUCCESS ``` 第一个建议链接必须在浏览器的地址字段中打开。 在加载的面板中输入 `?` ,然后按“Execute”(执行)按钮。 应用程序随后会显示命令示例。 ![](https://lh5.googleusercontent.com/Tsh6XG7TAcQJHcxWPFIWU8FK6rPFYhxzTvxtiKvjw_QAKxGicy_sJt0WhTcG8zBXNvkQzLlRQPTN4juAk8vOn3gyUXJREfgPs9rqUoM8) ### 命令 在面板中,您可以运行实用工具,查看和编辑 global,以及执行查询。 每次启动都保存在命名空间上下文的历史记录中,因此可以找到并重复。 在此上下文中,“启动”表示开始执行命令,命令表示我们在面板中输入的所有内容。 下面的屏幕截图显示了 global 数组 `^%apptools.History` 查看命令的示例 ![](https://lh4.googleusercontent.com/Viy-pXX3dVlNrfUX7SV4Alxb9pM3I-uDKAYgHRVJKP1hK9BuvkMIuP6oPfDNYrmJb-VTl8b12Fy61q63O-nH0FYG2u8zIeux2e-vvl1h) 如您所知,自动错误检测和通知可以由流行的解决方案(例如 Prometheus)处理。 但通常可以通过视觉评估错误的严重性。 我经常需要快速获取所有命名空间中的生产错误信息。 为此,我实现了一个实用工具: `##class(apptools.core.Production).FindAndDrawAllErr` 这会启动一个每日搜索请求,用于查找每个包含工作产品的命名空间中的错误,并允许通过快速转换到可视化跟踪来查看这些错误。 您可以在 apptools 面板中像运行其他任何程序一样运行此实用工具,只需加上 `xec` 前缀。 ![](https://lh3.googleusercontent.com/0olzck-lNvNLsCwBphoTWLwZdSZJrNpb3qbkul4WuuXD9NnMnwpXofCsay9FxVW8S4iWvZD7L3z-s5UrKpicBofeXUrHsAfeQrnkEU8C-fjXqcdV3dmVGBcZOtgnSuFxWAHI-2Dr) 所有有用命令都可以保存在作用域上下文的 global 扩展中,以便随时查找和重复。 ![](https://lh4.googleusercontent.com/qBRtuZL_gOFOZD92CQOr0-w-NH8PfpVhIpQZYZENmblg8_jpW-dN_pF7bKiPAcWjkE3Tew6pU0k0NsLelUE1KFcCd4Xhl3bF4SjNdtttUGqNq0_eW6GtTIiP9iBx7bjJ2UnAkrF8) ### Global apptools-admin 应用程序的很大一部分专门用于处理 global。 可以按倒序查看 global,还可以对链接和数据应用筛选。 显示的注释可以进行编辑或删除。 ![](https://lh4.googleusercontent.com/_FfwdGX_A11k4ue8vZ51_3qwuVvTJd8a0UgFqDPsRJICYuUGmcRMFjOxdG1sdHkLJR3Ea7m30BHSpx33wjDDCd5qVvN01ewWUefSfgNaTzA9Z9HK2iFdYmZZ9yLYuTlTSHFAGfqJ) 您可以在 global 名称后输入 `*` 通配符,以获得具有附加特征的 global 列表。 第二个 `*` 将添加一个新字段“Allocated MB”(已分配 MB)。 第三个将添加“Used MB”(已使用 MB)字段。 此语法解析为两个报告的结合,星号将通常较长的报告分成易管理的部分。 ![](https://lh6.googleusercontent.com/1osTx0tWcdQlteMHlFjIw3K6SEjH_3gO6EpTUEsfyPgR3_ns8LR3mMIPQGt31ToANPqx0fB_Fkjh6tc6WeUSwS9_8bYx5UgRjHnOkUF0o0izVz7dBB9eok2skmsCoWZbeB7gk_kY) 当您获取 global 列表形式的报告时(上面的屏幕截图中),可以点击活动链接来查看 global 本身。 还可以在管理门户中点击“`Permission`”(权限)字段中的 `R` 或 `W`,以标准方式查看和编辑 global。 通常,在调试项目时,对 global 的写操作用于记录变量和对象的状态。 为此,我使用特殊宏: `set $$$AppL("MSW","anyText")=$$$AppObJs(%request)` 在此示例中,`$$$AppL` 为一个带 `^log` 前缀的 glob 以及索引值中的日期和时间形成链接。 `$$$AppObJs` 是对象序列化宏。 ![](https://lh4.googleusercontent.com/AOTb2Axpzo_YlYNJacWM4k9RAdO0OmYlkYjnUtvEWM3Djc9VQL6NTuEo1mXR5m5K-PtHtsRVUXNwsd7lwkKjuicOvRCq5j2Mwx5P2eBN8lpyPiFacue4riVFkmakPidY5P5-Iyrw) 您可以在面板中查看协议 global,对象可以在窗口中以完全格式化的形式显示。 ### 查询 与 global 的使用几乎一样多的功能是查询。 通过输入命令形式的语句来运行此功能。 例如,可以执行一个 SQL 语句。 ![](https://lh3.googleusercontent.com/uPQs2IAuSpdORQXaxy_rlzSFmaB9RxKoiVWRGyLsG_tthobEpxU8uBunOxOTi695q9yDCHr0Xjez8IE-U8HKWKOzpvczDmmgaFrcmHfCpo6hMXsxJCP05LtdeohTiTrrooYuSRyh) 还可以将结果保存在 global `^mtempSQLGN` 中。 ![](https://lh4.googleusercontent.com/HE44MxizdxfluYQyuEvEs1k7vmSNganzvoxPWTGfYnjJwgYWD7u9fBlCmHUFT2LOPzfLp8vBC23yJyDDYvnMZU7gwIoJjKaVMhv5WQ8Da2-_F-NrNdjpcYyd4V0BakEiRCcrbejZ) 随后,global 中保存的结果可以显示在面板中。 ![[](https://lh3.googleusercontent.com/yJVXXpPBZMsT-eXI0FCaWs6f7YvWpMH4zBIKAv-ejtpCdAxqK8fSh3YEy_IbF-aPv9ijRLZXcgy026xLLEAS449CtVjzeKiv2coQa9eK7OmyIbCFOs7pLxJa7Trw525xO3DJFsMH) ### 将报告转换为 Excel 格式 标准管理门户缺少的一项功能是执行数据库 JDBC 或 ODBC 源中配置的查询,输出 XLS 格式的结果,然后将文件存档并通过电子邮件发送。 要在应用程序中实现此功能,只需在执行命令之前选中“Upload to Excel file”(上传到 Excel 文件)复选框。 这个功能为我的日常工作节省了很多时间,让我可以成功地将现成模块融入到新的应用程序和集成解决方案中。 ![](https://lh4.googleusercontent.com/LhyeRllHAL6q-rBiRNbCAgGOflKF8OZjomLMCjVapJ2qbvhouPS44dIHmbwt4I3-LmADhgaSNPg-u57am73bcdNGTH97rWtdL1FEmXHI5O9eQYyTBINjidT2H8TGIrXIc6kt4MnV) 要启用此功能,首先需要配置服务器上用于创建文件的路径、用户凭据以及邮件服务器。 为此,又需要编辑全局程序设置 `^%apptools.Setting` 的节点。 ![](https://lh4.googleusercontent.com/cTDe7pUN7bhHYiweuWbdL0bXsF98UoVCPsyLt84xlp-vCEH5edjvTgxiNfPIZbKRnCGpUk1m8mr0aPKHFMs0JdIDdwqS53wCF_997Z3KrRrBqv6jKCam0zlPkklC_YTxm8gRXhPb) ### 全局保存报告 通常,您需要将报告执行的结果保存到 global。 为此,可以使用以下程序: | | 函数 | | -------- | -------------------------------------- | | 对于 JDBC: | ##class(apptools.core.sys).SqlToDSN | | 对于 ODBC: | ##class(apptools.core.sys).SaveGateway | | 对于 SQL: | ##class(apptools.core.sys).SaveSQL | | 对于查询: | ##class(apptools.core.sys).SaveQuery | 例如,使用 `##class(apptools.core.sys).SaveQuery` 函数,将查询 `%SYSTEM.License:Counts` 的结果保存到 global `^mtempGN` 中。 ![](https://lh5.googleusercontent.com/VTwoteSkKE0MRg00CojD8HCpcK7CNAr8wAVldyVRp3dweYbXampTmhfAkwdIqGdj6H3zkJQ4_qdnCugQkkdpkga1hbXCghSHyZ5pIOufqwu5vcEv9YF3zdE__AwHaPN-5DeK2t9k) 然后可以使用以下命令在面板中显示已保存的内容: `result ^mtempGN("%SYSTEM.License:Counts", 0)` https://lh5.googleusercontent.com/KCIekwZw3guq79GWxVdHYdAbWQc4u97-dr-hWT26lYE2oEzUTSkwCE4ki1zvNqRFBg6dKQshSqcy3YSgUbjFKgX3v7Ecpa5Bm_NEQuZhP8Fn8p1gzrmAdTR-Cg9jBeVcNWGukW3a ### 增强功能模块 还有什么简化和自动化了我的工作? 就是让我能够在形成查询字符串时执行自定义模块的更改。 我可以将新功能即时嵌入到报告中,例如用于对数据执行其他操作的活动链接。 让我们看一些示例。 我们使用以下函数在浏览器中显示查询结果: `##class(apptools.core.LogInfoPane).DrawSQL` ![](https://lh3.googleusercontent.com/2s0tgxOgbOBLy-Pt1e8bx_gKJWNe5YQ6AWLRUCU02TcpTiUscKYeoBEce2qdzCGlbAPzIukRn5EuJ9jwu8eATPCH13zoR8A2fQoAWZfx3RpieD_8rACgikcCZpcIoAIofxlzv2mT) 让我们将字标记函数 `##class(apptools.core.LogInfo)`.MarkRed 添加到参数 5 中。 ![](https://lh6.googleusercontent.com/OyotzU3vmjoXw_MzA6amZbpPlpbL-li71OH5JRw7sAfiVoEsAvi8wSfY588kzdyXTURtGtinj0WvIKDhNLGyy50BD40E7NEQSpNv2Iv85lQisJaMBquvheuXVrMravp6OlNxkcqI) 同样,可以为输出补充其他功能,例如,活动链接或工具提示。 本解决方案中的 global 编辑器根据同样的原理实现。 以下是以表格形式输出 global 和查询的函数列表: | | 函数 | | ------------- | ----------------------------------------------------------------------------- | | 对于 global: | ##class(apptools.core.LogInfoPane).DrawArray("^mtempSQLGN") | | 对于 SQL: | ##class(apptools.core.LogInfoPane).DrawSQL("select * From %SYS.ProcessQuery") | | 对于查询: | ##class(apptools.core.LogInfoPane).DrawSQL("query %SYSTEM.License:Counts") | | 对于 global 结果: | ##class(apptools.core.LogInfoPane).DrawSQL("result ^mtempSQLGN") | 使用 apptools.core.Parameter 类 在安装了 apptools-admin 的实例的上下文中,此链接将在浏览器中打开 CSP 应用程序。 `http://localhost:52773/apptools/apptools.Form.Exp.cls?NSP=APP&SelClass=apptools.core.Parameter` 或在面板中选择活动链接。 ![](https://lh4.googleusercontent.com/dt3oFX7Aum3yuJ4lvOtmhUWqm55GyFPPRGbsW7phZWRAnnJkB5xE0CdD3ddFEnS0-5xzSD_ydNe2hXp8Eqk1R39aioTZunY7bymF4EkPfaukm86sfFb-YrQp5Mx_KOyU9sr9cGbR) 将加载 CSP 应用程序以编辑存储类的实例,在此示例中: `apptools.core.Parameter`。 ![](https://lh5.googleusercontent.com/OLXVridH04HDDbufXUp9kZ70h08ptXrRcvDRThemPEira4KANa2ECTVGUJm7nuc3crqAnerWcJMToyipqM4YZCcnwqWRVXbOFKN0ZakCvpqrpdMsQZ0yXtCBgUt8z2U_JOmKnSFF) ![](https://lh4.googleusercontent.com/8JO4JQRssC22LGhab6dZiG6PnD2NRYIQtYsY9zj-Z99IIHxVpekzsxfV3Pw04SgxEqto_JepTXcht6vBu17D834Z_7_Hh-Yr5GmXSOsI5axLf7vIHxUi-tmTwcJH9DFlomurpgCH) ### 通过表导航器创建 apptools.core.Parameter 在安装了 apptools-admin 的实例的上下文中,如果在浏览器中打开此链接: `http://localhost:52773/apptools/apptools.Form.Exp.cls?panel=AccordionExp&NSP=APP` 或在面板中选择活动链接。 ![](https://lh3.googleusercontent.com/5me2dJ5aItW6iixR4mBfVRMJHDZfXRnq_pkGrlmCtCTeKzsRx0MbopN0YcLdvEsoWs46Aqw_0fVJGk6L88AaFNWeajDgggpwYawRTbdUIhHRxWo7pFiv3dqj_JdO5wgmm_uZTL5_) 将加载 CSP 应用程序以导航存储类,并能够编辑它们。 ![](https://lh3.googleusercontent.com/TjtNmzFRS8fTOpsRU0XAXYCHYHNpenI9H1WsEPEtVz7bT2jhakKjsfdJ_inLXX-cBsu5PlKgSJjIS3VoHXD6dqzEm0PDrhy2eOPFT-BoHx6ToPB6Jio21lN1bloGk1xtdlRR7Gd-) ### 简单 CSP 应用程序的示例 在安装了 apptools-admin 的实例的上下文中,如果在浏览器中打开此链接: `http://localhost:52773/apptools/apptools.Tabs.PanelSample.cls` 或在面板中选择活动链接。 ![](https://lh3.googleusercontent.com/mqMOjz96bd2YmJdIQtdVYsZhYDFW73BMJtjQh2q1wzzKYrzE39kWGTd2-M0kpBQlxIT2bkv2V7o7ieIlyV7aU8XNF29oI3spIoLGJJAHOKppLrTVrrR2XwOJHAQgLXM3TEQPWGGj) 此示例还显示了编辑类实例 `apptools.core.Parameter` 的能力。 ![](https://lh4.googleusercontent.com/sFXN0QJJb1UuyNJPhykvDOJeOEWC3RrO7oV1dqYixKnPlgEDFJdBqj5bORhaXlftxvngbu-UdgCqvG2UEr7_hKUhjGtJk6jrDNgc43f7DwWCmuDnFubMuIcavHAh7Z1--R72Pf_Q) ### 图表 为了直观展示数据库的增长,应用程序提供了一个图表页面,显示每月测量的数据库大小。 该图表来源于 IRIS file.log(对于 Caché 则为 cconsole.log)中从当天向回“扩展”的记录。 程序会遍历协议,找到数据库扩展记录,并从当前数据库大小中减去增量的兆字节。 最终生成数据库增长的图表。 例如,下面的屏幕截图显示了 InterSystems IRIS 中通过协议文件形成的事件图。 ![](https://lh4.googleusercontent.com/EbO0ZVyJwj1EgKF9SR6BpKPyBERj3cNgK4ckrDrzVWVu35LUlQAINvsbArTJ946XQWBhDUzS_dm4m3ize-RM7EjyRLQkesaNvNQOvK8FuUGwKx_8gqYlCMvmC2Xy2ih0xgZKx_q-) 下面是另一个示例:系统中的事件时间表,基于系统协议 file.log (cconsole.log)。 ![](https://lh6.googleusercontent.com/s3Uz-F88rFnBWSCS5_m4vtCQL9kdS2dEL101oWtlfmmNpfjF1PgtPppI2GC1g3syXIr39X1dUBO0O-gC5mDXcT1k6xOkXrz19TeRqpRAWrNG_FL6kMoyAZqS2N7mIDjG2BKpPy_j) ### 总结 我们在本文中讨论的应用程序旨在帮助我执行日常任务。 它包括一组模块,您可以将它们用作自定义管理员工具的构建块。 如果您觉得它对您的工作有用,我会非常高兴。 欢迎将愿望和建议作为任务添加到项目[仓库](https://github.com/SergeyMi37/apptools-admin)。
文章
Michael Lei · 四月 24, 2021

置顶--InterSystems 中文开发者社区精华文章集锦

欢迎大家将相关的经验在这个讨论区分享。 板块 文章列表 征文大赛作品集锦 2022年首届InterSystems 技术征文大赛集锦 2023年第二届InterSystems 技术征文大赛集锦 官方文档 我司即将推出中文官方文档门户,欢迎大家把需要的官方文档发在评论区,我们会优先发布。谢谢! IRIS 2021 最新技术文档 First Look 1 技术概要 IRIS 2021 中文文档PDF下载 InterSystems IRIS for Health 2023 英文文档PDF下载 基础知识与概念 InterSystems-常用术语 多语言字符集系列文章--第一篇 多语言字符集和相关标准简史 基础系列--第一章 SQL中使用的符号 基础系列--Object Script 基础知识(一) 基础系列--InterSystems SQL 的使用 - 第一部分 - 架构及特性介绍 基础系列--WebGateway系列(1): Web Gateway介绍 基础系列 DeepSee 的开发 - 第一部分 - Cube 基础系列--访问IRIS数据平台的四种方式 InterSystems IRIS 的面向对象数据库特性 InterSystems IRIS - 适用于实时人工智能/机器学习的多功能通用平台 使用支持SSL的ODBC连接IRIS数据库 容器中的InterSystems IRIS Docker简介 在集成产品中压缩解压文件 无代码实现SQL业务服务和业务操作 通用TCP业务服务和业务操作 通用RESTful 业务服务和业务操作 通用SQL 业务服务和业务操作 运维与常见问题 InterSystems 最佳实践系列文章 IRIS/Healthconnect-高可用机制-mirror-的配置 系统运维、管理常见问题FAQ系列 运维好文--InterSystems 数据平台互操作功能运行维护管理基础 运维好文--集成平台实例中有哪些文件在占用磁盘? 安全、等保、审计相关系列 虚拟化大型数据库 - VMware CPU 容量规划 InterSystems 数据平台的容量规划和性能系列文章 已经解决的问题清单 使用Prometheus监控Cache集群 医院信息化建设实战教程:如何在不允许使用Git的情况下自动备份代码/自动执行代码? 关于Caché中查看关键锁的几种方式 镜像备机长时间宕机的处理 如何维护变化频繁表的位图索引 将 pButtons 数据提取到 CSV 文件以便绘制图表 Yape - 另一个pButtons 提取程序(自动创建图表) 数据迁移工具: 从Postgres 到 IRIS 数据迁移工具:从MySQL 到 IRIS 开发与创新 CDC系列:使用Dejournal Filter在InterSystems IRIS/Caché上通过Mirroring实现CDC功能实操--HealthConnect中创建HTTP服务创新--基于Docker的一体化集成AI环境中部署机器学习/深度学习模型 创新--面向 Google Cloud Platform (GCP) 的 InterSystems IRIS 示例参考架构 创新--在 Windows 主机上运行的 Hyper-V Ubuntu 虚拟机中配置 Docker 使用环境 创新-- 新一代医疗数据互操作标准FHIR系列文章 FHIR创新应用示例:使用FHIR Cloud Server和IRIS for Health对妊娠糖尿病进行连续血糖监测 科研--用IRIS IntegratedML(一体化机器学习)来预测肾病的Web应用 IRIS如何进行CRUD操作 如何调用Ensemble/IRIS内置的HL7 V2 webservice - Java,PB9,Delphi7样例 IRIS与Caché的23种设计模式 10分钟快速开发一个连接到InterSystems IRIS数据库的C#应用 在IRIS中联合运用 OCR 与 NLP 技术 物联网 (IOT) 在 InterSystems IRIS 平台上的应用 现有系统通过使用FHIR适配器提供FHIR服务 SqlDbx连接IRIS攻略 使用Visual Studio Code访问 IRIS 终端 Ensemble使用sql+global实现简单分页 通过XSL自动生成消息模型 IRIS自动安装集群--manifest(安装清单) JWT - JSON Web Token Authentication介绍 如何根据ID重建索引 使用 InterSystems IRIS 实现 Data Fabric架构 在 InterSystems IRIS 中创建具有超过999个属性的类/表 FHIR相关 FHIR CDS Hooks FHIR Profile FHIR 生态 FHIR与微服务架构 NHS FHIR实践案例和经验 在InterSystems IRIS 医疗版的FHIR服务器上测试和开发SMART on FHIR应用 InterSystems IRIS 医疗版创建FHIR服务器 使用一个命令创建 InterSystems FHIR 服务器 在本地 K8s上部署一台FHIR服务器 创建FHIR REST 客户端 使用iris-fhir-client应用程序创建患者和患者观察 【视频】FHIR标准和国际上基于FHIR的互联互通实践 现有系统通过使用InterSystems FHIR 适配器提供FHIR服务 使用 Synthea 生成 FHIR测试数据 FHIR客户端使用嵌入式Python连接FHIR服务器 如何发布FHIR文档(医疗信息表、出院小结等) 借助 VS Code中的IntelliSense自动完成功能,通过使用FHIR Schema创建和验证FHIR资源 消息转换服务-轻松实现从HL7 V2 转换为 FHIR 将 ObjectScript 持久化类暴露位 FHIR代码系统和值集 本地化 Caché实现SM3密码杂凑算法 在国产系统上安装Healthconnect2021 HEALTHSHARE2018版如何实现AES(CBC)的HEX输出,并可以实现加密和解密 行业观察与洞见 精华文章--《数据二十条》的号角声 论集成标准的选择对医院信息集成平台建设的影响 医疗行业的生态创新:如何实现数据利用和应用创新 精华文章--从软件架构发展谈业务集成技术演进与展望 精华文章--漫谈应用集成的现在与未来 翻译文章:什么是智慧医院数字孪生? 医疗行业数字化转型 —谈谈微服务架构 医院数字化转型之数智底座建设思路(在陕西省数字医学数字化转型论坛上的分享) 行业前沿系列翻译文章--EPIC 电子病历系统: FHIR, API, 互操作性和资源 行业前沿--利用数据编织应对挑战,创造数据价值 医疗行业的生态创新:如何实现数据利用和应用创新 转载:Epic的Cosmos如何用去识别化的数据支持临床研究 前沿探讨--大模型GPT 对医疗行业互操作性协议的影响? 国际卫生信息互操作性标准发展简史 其他 社区文章汇总--跟着社区学习InterSystems 技术 产品对比——Gartner DBMS 魔力象限中的主要领先数据库产品功能对比 产品对比--企业软件的“大众点评”之最新Gartner 云数据管理系统对比,国内医疗信息行业主流的Hadoop(Cloudera)vs Oracle vs Sql Server vs InterSystems Cache 产品对比--Gartner Peer Insight 华山论剑之应用集成平台--InterSystems vs MS vs IBM 学习系列 IRIS/Healthconnect-高可用机制-mirror-的配置 跟版主学caché——大型史诗级免费技术培训caché百讲 git-github入门学习系列 IRIS 快速入门系列讲座 WebGateWay 学习系列 学技术、练听力,尽在InterSystems系联在线培训广播电台 Intersystems IRIS for Health 数据平台医疗版最新在线培训课程 CDC系列 ISC 中国在B站培训视频 如何在社区学习? 初学者资源库 FHIR标准和国际基于FHIR的互联互通实践 在InterSystems IRIS 中使用Python Python 和 ObjectScript 中消息响应时间的对比测试 使用Python访问 InterSystems IRIS 数据库 将Python JDBC 连接到 IRIS数据库 - 快速笔记 将Python ODBC 连接到 IRIS 数据库 - 快速笔记2 使用 pyodbc将 Python 应用程序连接到 InterSystems IRIS 使用 IRIS Native SDK for Python 遍历 IRIS Global数据结构 使用 IRIS Native SDK for Python 调用类方法 嵌入式Python 概述 使用嵌入式Python系列 使用嵌入式Python进行 Web 抓取 使用嵌入式 Python 实现 InterSystems IRIS 互操作性 使用嵌入式Python动态创建 HL7 消息 使用嵌入式Python生成数据流 使用嵌入式Python创建存储过程 InterSystems IRIS 嵌入式 Python 模板 嵌入式Python重新加载更新后的Python模块 使用嵌入式Python 访问广利门户仪表盘并在网页上显示 Caché 表数据 使用 SQLAlchemy 将表传输到IRIS 或从 IRIS中获取表 SQLAlchemy - 将Python 和 SQL 与 IRIS 数据库一起使用的最简单方法 在Python 上使用IRIS REST API 进行 SQL 迁移 使用 IRIS 和Python gTTS实现文本转化声音的 REST 服务 基于IRIS 的 Python 实践与示例 使用 IRIS 和 Python 创建聊天机器人 InterSystems IRIS 2021.2+Python 代码样例 使用嵌入式 Python 教程 基于IRIS的Python 全球疫情大数据仪表盘样例 未来智慧医院畅想--利用Python进行人脸识别和情绪感知 调研—— InterSystems 客户服务满意度调研(长期有效) 互操作系列 消息统一管理 孤立消息管理 HTTP服务 开发系统接口 IRIS 系列 2021版最新官方系列文档 权限管理 容量和性能规划 超融合规划 Web Gateway 数据同步和容灾系列 SOAP 服务 开发 ObjectScript 系列 Object & SQL 运维 系统运维常见问题 B站视频 其他Ensemble相关
文章
Hao Ma · 一月 10, 2021

InterSystems 最佳实践系列---APM – 监控 SQL 查询性能

自 Caché 2017 以后,SQL 引擎包含了一些新的统计信息。 这些统计信息记录了执行查询的次数以及运行查询所花费的时间。 对于想要对包含许多 SQL 语句的应用程序的性能进行监控和尝试优化的人来说,这是一座宝库,但访问数据并不像一些人希望的那么容易。 本文和相关的示例代码说明了如何使用这些信息,以及如何例行提取每日统计信息的摘要,并保存应用程序的 SQL 性能的历史记录。 记录了什么? 每次执行 SQL 语句时,都记录花费的时间。 这是非常轻量的操作,无法关闭。 为了最大程度地降低开销,统计信息保留在内存中并定期写入磁盘。 数据包括一天中执行查询的次数以及所花费的平均时间和总时间。 数据不会立即写入磁盘,并且在写入之后,统计信息将由“更新 SQL 查询统计信息”任务更新,该任务通常计划为每小时运行一次。 该任务可以手动触发,但是如果你希望在测试查询时实时查看统计信息,则整个过程需要一点耐心。 警告:在 InterSystems IRIS 2019 及更早版本中,不会针对已使用 %Studio.Project:Deploy 机制部署的类或例程中的嵌入式 SQL 收集这些统计信息。 示例代码不会有任何中断,但这可能会使你产生误导(我被误导过),让你以为一切正常,因为没有查询显示为高开销。 如何查看信息? 你可以在管理门户中查看查询列表。 转到 SQL 页面,点击“SQL 语句”选项卡。 对于你正在运行并查看的新查询,这种方式很好;但是如果有数千条查询正在运行,则可能变得难以管理。 另一种方法是使用 SQL 搜索查询。 信息存储在 INFORMATION_SCHEMA 模式的表中。 该模式含有大量表,我在本文的最后附上了一些 SQL 查询示例。 何时删除统计信息? 每次重新编辑查询时会删除其数据。 因此对于动态查询,这可能意味着清除缓存的查询时。 对于嵌入式 SQL,则意味着重新编译在其中嵌入 SQL 的类或例程时。 在活跃的站点上,可以合理预期统计信息将保存超过一天,但是存放统计信息的表不能用作运行报告或长期分析的长期参考源。 如何汇总信息? 我建议每天晚上将数据提取到永久表中,这些表在生成性能报告时更易于使用。 如果在白天编译类,可能会丢失一些信息,但这不太可能对慢速查询的分析产生任何实际影响。 下面的代码示例说明了如何将每个查询的统计信息提取到每日汇总中。 它包括三个简短的类: * 一个应在每晚运行的任务。 * DRL.MonitorSQL 是主类,用于从 INFORMATION_SCHEMA 表提取数据并存储。 第三个类 DRL.MonitorSQLText 是一个优化类,它存储一次(可能很长的)查询文本,并且只将查询的哈希存储在每天的统计信息中。 示例说明 该任务提取前一天的信息,因此应安排在午夜后不久执行。 你可以导出更多历史数据,只要其存在。 要提取过去 120 天的数据 Do ##class(DRL.MonitorSQL).Capture($h-120,$h-1) 该示例代码直接读取全局 ^rIndex,因为最早版本的统计信息未将日期公开给 SQL。 我所包括的变体将循环实例中的所有命名空间,但这并不总是合适的。 如何查询已提取的数据 提取数据后,您可以通过运行以下语句查找最繁重的查询 SELECT top 20 S.RunDate,S.RoutineName,S.TotalHits,S.SumpTIme,S.Hash,t.QueryText from DRL.MonitorSQL S left join DRL.MonitorSQLText T on S.Hash=T.Hash where RunDate='08/25/2019' order by SumpTime desc   此外,如果选择了开销大的查询的哈希,可以通过以下语句查看该查询的历史记录   SELECT S.RunDate,S.RoutineName,S.TotalHits,S.SumpTIme,S.Hash,t.QueryText from DRL.MonitorSQL S left join DRL.MonitorSQLText T on S.Hash=T.Hash where S.Hash='CgOlfRw7pGL4tYbiijYznQ84kmQ=' order by RunDate   今年早些时候,我获取了一个活跃站点的数据,然后查看了开销最大的查询。 有一个查询的平均时间不到 6 秒,但每天被调用 14000 次,加起来每天消耗的时间将近 24 小时。 实际上,一个核心完全被这个查询占用。 更糟糕的是,第二个查询要花一个小时,它是第一个查询的变体。   运行日期 例程名称 总命中次数 总时间 哈希 查询文本(有节略) 03/16/2019   14,576 85,094 5xDSguu4PvK04se2pPiOexeh6aE= DECLARE C CURSOR FOR SELECT * INTO :%col(1) , :%col(2) , :%col(3) , :%col(4)  … 03/16/2019   15,552 3,326 rCQX+CKPwFR9zOplmtMhxVnQxyw= DECLARE C CURSOR FOR SELECT * INTO :%col(1) , :%col(2) , :%col(3) , :%col(4) , … 03/16/2019   16,892 597 yW3catzQzC0KE9euvIJ+o4mDwKc= DECLARE C CURSOR FOR SELECT * INTO :%col(1) , :%col(2) , :%col(3) , :%col(4) , :%col(5) , :%col(6) , :%col(7) , 03/16/2019   16,664 436 giShyiqNR3K6pZEt7RWAcen55rs= DECLARE C CURSOR FOR SELECT * , TKGROUP INTO :%col(1) , :%col(2) , :%col(3) , .. 03/16/2019   74,550 342 4ZClMPqMfyje4m9Wed0NJzxz9qw= DECLARE C CURSOR FOR SELECT … 表 1:客户站点的实际结果   INFORMATION_SCHEMA 模式中的表 除了统计信息外,此模式中的表还会跟踪查询、列、索引等的使用位置。 通常,SQL 语句是起始表,它的连接方式类似于“Statements.Hash=OtherTable.Statement”。 直接访问这些表以查找一天中开销最大的查询,这一操作的等效查询是...   SELECT DS.Day,Loc.Location,DS.StatCount,DS.StatTotal,S.Statement,S.Hash FROM INFORMATION_SCHEMA.STATEMENT_DAILY_STATS DS left join INFORMATION_SCHEMA.STATEMENTS S on S.Hash=DS.Statement left join INFORMATION_SCHEMA.STATEMENT_LOCATIONS Loc on S.Hash=Loc.Statement where Day='08/26/2019' order by DS.stattotal desc   无论你是否考虑建立一个更系统的过程,我都建议每个使用 SQL 处理大型应用程序的人今天都运行这个查询。 如果某个特定查询显示为高开销,则可以通过运行以下语句获取历史记录 SELECT DS.Day,Loc.Location,DS.StatCount,DS.StatTotal,S.Statement,S.Hash FROM INFORMATION_SCHEMA.STATEMENT_DAILY_STATS DS left join INFORMATION_SCHEMA.STATEMENTS S on S.Hash=DS.Statement left join INFORMATION_SCHEMA.STATEMENT_LOCATIONS Loc on S.Hash=Loc.Statement where S.Hash='jDqCKaksff/4up7Ob0UXlkT2xKY=' order by DS.Day     每日提取统计信息的代码示例 标准免责声明 - 此示例仅用于说明。 不对其提供支持,也不保证其有效。 Class DRL.MonitorSQLTask Extends %SYS.Task.Definition{Parameter TaskName = "SQL Statistics Summary";Method OnTask() As %Status{              set tSC=$$$OK              TRY {                             do ##class(DRL.MonitorSQL).Run()              }              CATCH exp {                            set tSC=$SYSTEM.Status.Error("Error in SQL Monitor Summary Task")              }              quit tSC }}   Class DRL.MonitorSQLText Extends %Persistent{/// Hash of query textProperty Hash As %String;  /// query text for hashProperty QueryText As %String(MAXLEN = 9999);Index IndHash On Hash [ IdKey, Unique ];} /// Summary of very low cost SQL query statistics collected in Cache 2017.1 and later. /// Refer to documentation on "SQL Statement Details" for information on the source data. /// Data is stored by date and time to support queries over time. /// Typically run to summarise the SQL query data from the previous day.Class DRL.MonitorSQL Extends %Persistent{/// RunDate and RunTime uniquely identify a runProperty RunDate As %Date;/// Time the capture was started/// RunDate and RunTime uniquely identify a runProperty RunTime As %Time;/// Count of total hits for the time period for Property TotalHits As %Integer;/// Sum of pTimeProperty SumPTime As %Numeric(SCALE = 4);/// Routine where SQL is foundProperty RoutineName As %String(MAXLEN = 1024);/// Hash of query textProperty Hash As %String;Property Variance As %Numeric(SCALE = 4);/// Namespace where queries are runProperty Namespace As %String;/// Default run will process the previous days data for a single day./// Other date range combinations can be achieved using the Capture method.ClassMethod Run(){              //Each run is identified by the start date / time to keep related items together                           set h=$h-1              do ..Capture(+h,+h)}/// Captures historic statistics for a range of datesClassMethod Capture(dfrom, dto){              set oldstatsvalue=$system.SQL.SetSQLStatsJob(-1)                             set currNS=$znspace                set tSC=##class(%SYS.Namespace).ListAll(.nsArray)                set ns=""      set time=$piece($h,",",2)      kill ^||TMP.MonitorSQL                do {                               set ns=$o(nsArray(ns))                               quit:ns=""                               use 0 write !,"processing namespace ",ns                               zn ns                                           for dateh=dfrom:1:dto {                                                          set hash=""                                                          set purgedun=0                                                          do {                                                                        set hash=$order(^rINDEXSQL("sqlidx",1,hash))                                                                        continue:hash=""                                                                        set stats=$get(^rINDEXSQL("sqlidx",1,hash,"stat",dateh))                                                                        continue:stats=""                                                                        set ^||TMP.MonitorSQL(dateh,ns,hash)=stats                                                                                                                                 &SQL(SELECT  Location into :tLocation FROM INFORMATION_SCHEMA.STATEMENT_LOCATIONS WHERE Statement=:hash)                                                                        if SQLCODE'=0 set Location=""                                                                        set ^||TMP.MonitorSQL(dateh,ns,hash,"Location")=tLocation                                                                                                                                 &SQL(SELECT  Statement INTO :Statement FROM INFORMATION_SCHEMA.STATEMENTS WHERE Hash=:hash)                                                                        if SQLCODE'=0 set Statement=""                                                                        set ^||TMP.MonitorSQL(dateh,ns,hash,"QueryText")=Statement                                                          } while hash'=""                                                                                                    }                } while ns'=""                zn currNS                set dateh=""                do {                               set dateh=$o(^||TMP.MonitorSQL(dateh))                               quit:dateh=""                               set ns=""                               do {                                             set ns=$o(^||TMP.MonitorSQL(dateh,ns))                                             quit:ns=""                                             set hash=""                                             do {                                                         set hash=$o(^||TMP.MonitorSQL(dateh,ns,hash))                                                          quit:hash=""                                                         set stats=$g(^||TMP.MonitorSQL(dateh,ns,hash))                                                          continue:stats=""                                                          // The first time through the loop delete all statistics for the day so it is re-runnable                                                          // But if we run for a day after the raw data has been purged, it will wreck eveything                                                          // so do it here, where we already know there are results to insert in their place.                                                          if purgedun=0 {                                                                        &SQL(DELETE FROM websys.MonitorSQL WHERE RunDate=:dateh )                                                                        set purgedun=1                                                          }                                                                                                                   set tObj=##class(DRL.MonitorSQL).%New()                                                          set tObj.Namespace=ns                                                          set tObj.RunDate=dateh                                                          set tObj.RunTime=time                                                          set tObj.Hash=hash                                                          set tObj.TotalHits=$listget(stats,1)                                                          set tObj.SumPTime=$listget(stats,2)                                                          set tObj.Variance=$listget(stats,3)                                                          set tObj.Variance=$listget(stats,3)                                                                                                                  set queryText=^||TMP.MonitorSQL(dateh,ns,hash,"QueryText")                                                         set tObj.RoutineName=^||TMP.MonitorSQL(dateh,ns,hash,"Location")                                                                                                             &SQL(Select ID into :TextID from DRL.MonitorSQLText where Hash=:hash)                                                          if SQLCODE'=0 {                                                                        set textref=##class(DRL.MonitorSQLText).%New()                                                                        set textref.Hash=tObj.Hash                                                                        set textref.QueryText=queryText                                                                        set sc=textref.%Save()                                                          }                                                                                                                  set tSc=tObj.%Save()                                                                                                                   //avoid dupicating the query text in each record because it can be very long. Use a lookup                                                          //table keyed on the hash. If it doesn't exist add it.                                                          if $$$ISERR(tSc) do $system.OBJ.DisplayError(tSc)                                                                                                                   if $$$ISERR(tSc) do $system.OBJ.DisplayError(tSc)                                             } while hash'=""                               } while ns'=""                                                                         } while dateh'=""                                                           do $system.SQL.SetSQLStatsJob(0)}Query Export(RunDateH1 As %Date, RunDateH2 As %Date) As %SQLQuery{SELECT S.Hash,RoutineName,RunDate,RunTime,SumPTime,TotalHits,Variance,RoutineName,T.QueryText              FROM DRL.MonitorSQL S LEFT JOIN DRL.MonitorSQLText T on S.Hash=T.Hash              WHERE RunDate>=:RunDateH1 AND RunDate