搜索​​​​

文章
姚 鑫 · 九月 27, 2022

第四十五章 配置第三方软件以与 InterSystems 产品结合使用

# 第四十五章 配置第三方软件以与 InterSystems 产品结合使用 产品通常在与非 工具一起运行的环境中运行,我们的产品与此类工具之间的交互可能会产生有害影响。 关于最佳、可靠部署配置的指导假定我们的产品可以在不受第三方工具干扰的情况下进行部署。例如, 发现用于安全、系统监控或病毒扫描的软件可能会影响我们产品的安装、性能和功能。对于直接与属于 产品的一部分或被 产品使用的文件进行交互的工具(例如病毒扫描程序)尤其如此。 了解客户面临的业务、合规性和其他要求会影响有关在给定环境中运行哪些软件以及如何配置此类软件的决策。一般来说, 建议我们产品的服务器端安装通过物理安全和隔离来保护。这种保护应该减少对其他工具的需求,或者至少减少它们运行的频率。 病毒扫描仪观察: 1. 为了交付经过病毒检查的软件, 产品在经过消毒的环境中交付给我们的客户,并通过提供校验和进行验证。 2. 性能影响。 [对策] 出于扫描目的,排除以下文件和目录: - `WIJ` 文件和包含 `WIJ` 文件的目录`*`。 - 本指南“配置 `IRIS`”一章中的所有数据库文件 (`.DAT`) 和包含数据库文件的目录*(请参阅配置数据库)。 - 存储或处理日志文件的任何目录`*`。 - `IRIS®` 数据平台运行所需的任何其他文件`/`目录`*`。例如备用日志目录*(请参阅数据完整性指南中的“日志”),或业务服务或生产使用的任何目录*。 3. 可执行文件的误报。 [对策] 出于扫描目的,排除所有 `irisdb.exe` 文件和包含 `irisdb.exe` 文件的目录。 警告:从恶意软件扫描中排除项目可能会将漏洞引入受保护的设备和应用程序。客户承担配置恶意软件保护的所有责任。 最后,当 发现第三方软件与我们的产品之间的交互对我们的产品行为产生负面影响时,我们会将这些问题报告给第三方供应商。
公告
Claire Zheng · 九月 19, 2022

欢迎来了解一下 InterSystems Ideas ——我们的官方反馈门户

开发者社区的同学们,大家好! 我们一直以来都有一个想法——改进收集、分析和回应开发者社区成员们的产品改进请求的过程。我们知道,我们需要一个良好的用户体验,甚至更好的内部流程,来确保收集、听取和响应最好的想法。现在,这个想法终于实现了! 我们在此向您介绍 InterSystems官方反馈门户 💡 >> InterSystems Ideas << 💡 InterSystems Ideas InterSystems Ideas是一个全新的、推动改进的渠道,您可以通过它向我们提交与InterSystems服务(文档、开发社区、全球大师等)相关的产品改进请求和想法,看看其他人提交了什么,为你喜欢的想法投票,投票给你最喜欢的,并从InterSystems获得反馈。 我们开始积极开发和推广创意门户网站InterSystems Ideas和您的创意。我们希望这可以为您提供一个公开的方式来获得我们的产品经理和社区成员的反馈。 ✅ 获得投票最多的想法会得到产品管理部门的评审。 来社区分享你的想法吧!通过投票和评论为其他想法提供贡献——投票越多,影响力越大! 点击看看创意网站 InterSystems Ideas portal!
公告
Claire Zheng · 七月 1, 2022

InterSystems 2022 Full Stack开发者大赛

大家好!欢迎参加InterSystems第21届开发者大赛! 🏆 InterSystems 2022 Full Stack开发者大赛 🏆 时间: 2022年6月27日-7月17日(美东时间) 奖金:$10,000 主题 💡 Full Stack 应用 💡 以InterSystems IRIS, InterSystems IRIS For Health(医疗版)或 IRIS Cloud Service为后端开发一个Full Stack解决方案。所谓的Full Stack,即通过REST API、Native API、ODBC/JDBC或嵌入式Python在InterSystems IRIS中插入、更新或删除数据的前端web或移动应用程序。 还有呢? 这次我们希望邀请开发者们以自己的专长来解决一个全球面临的挑战!我们鼓励你加入这次竞赛,提交聚焦于气候变化问题的解决方案:1) 如果您提交的应用能够解决一个与全球变暖或气候变化相关的问题,将收到一份特别奖励;2) 如果您准备并将在Open Exchange提交一个与全球变暖或气候变化相关的数据集,也会得到额外奖励。 那么,我们期待您的创新方案,共同建设一个可持续的发展的世界。用您的专长,为气候问题来制定解决方案吧! 基本要求: 有效应用程序:100%全新的Open Exchange Apps或已有的应用程序(但有显著提升)。所有参赛者/团队提交的应用程序只有经过我们团队的审核之后才会被批准参赛。 该应用可以在 IRIS Community Edition or IRIS for Health Community Edition or IRIS Advanced Analytics Community Edition上运行。 该应用需开源并在GitHub上发布。 该应用的README文件应为英文,包含安装步骤,并包含视频demo或/和应用程序如何运行的描述。 奖品 1. 专家提名奖(Experts Nomination)- 获奖者由我们特别挑选的专家团选出: 🥇 第1名 - $4,000 🥈 第2名 - $2,000 🥉 第3名 - $1,000 🌟 第4-15名- $100 2. 社区提名奖(Community Nomination)- 获得总投票数最多的应用: 🥇 第1名 - $1,000 🥈 第2名 - $750 🥉 第3名 - $500 ✨ 所有获奖者都将获得Global Masters徽章! 注意:如果同时多位参赛者获得同样的票数,均被视为优胜者,将平分奖金 关键参赛节点 🛠 应用开发、提交阶段 2022年6月27日 00:00 ( 美东时间): 竞赛启动. 2022年7月10日 23:59 ( 美东时间): 提交截止 ✅ 投票阶段 2022年7月11日 00:00 ( 美东时间): 投票开始 2022年7月17日 23:59 ( 美东时间): 投票截止 注意:在整个参赛期间(开发与投票期间),开发者可持续提升其应用 谁可以参加? 任何开发者社区的成员均可参加,InterSystems内部员工除外(InterSystems contractor员工可以参加)。还没有账号?现在来建一个! 👥 开发者可以组团 创建一个协作应用程序,组团限定人数为2-5人。 请注意,要在您的README文件中标注您的团队成员——社区用户profile 资源助力: ✓ 适用于Full Stack应用的InterSystems IRIS Docker模板: IRIS Full Stack template Basic InterSystems IRIS Docker template IRIS REST API template Native API template IntegratedML template IRIS Analytics template isc-ipm-js isc-perf-ui isc-json isc-rest isc-codetidy ✓ 在线课程: Implementing RESTful Applications ✓ 视频: REST API design and Development REST API in 5 minutes Data-Driven Web Apps ✓ IRIS初学者: Build a Server-Side Application with InterSystems IRIS Learning Path for beginners ✓ ObjectScript Package Manager (ZPM) 初学者: How to Build, Test and Publish ZPM Package with REST Application for InterSystems IRIS Package First Development Approach with InterSystems IRIS and ZPM ✓ 如何将您的APP提交给大赛: 如何在InterSystems Open Exchange上发布应用程序 如何把参赛APP提交给大赛 需要帮助? 加入InterSystems的 Discord server频道,或跟帖评论提出您的问题! 期待您的精彩提交!祝好运 👍 参与此次竞赛,您同意 遵守相关条款,请认真阅读。
公告
Claire Zheng · 十一月 17, 2022

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

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(创意社区),提出你的观点,为你认同的创意投票! 下期见!
公告
Jingwei Wang · 一月 26

2023 年 InterSystems 开发者工具大赛的技术奖励

以下是 2023 年 InterSystems 开发者工具大赛的技术红利,您可以在投票中获得额外加分: 嵌入式 Python的使用 Docker容器的使用 ZPM 包部署 在线演示 代码质量通过 开发者社区文章 开发者社区第二篇文章 上传 YouTube 视频 第一次贡献 请参阅下面的额外加分项详细信息: 嵌入式 Python的使用 - 3 分 在您的应用程序中使用嵌入式 Python,可以获得 3 分加分。您至少需要 InterSystems IRIS 2021.2及以上版本。 Docker 容器的使用 - 2 分 如果应用程序使用在 docker 容器中运行的 InterSystems IRIS,则该应用程序将获得“Docker 容器”奖励。这是最简单的模板。 ZPM 包部署 - 2 分 如果您为您的全栈应用程序构建和发布 ZPM(ObjectScript 包管理器)包,您可以获得2分加分,以便它可以使用如下方式部署: zpm "install your-multi-model-solution" 已安装的ZPM 客户端命令,请参考: ZPM客户端。文档。 项目的在线演示 - 2 分如果您将项目作为在线演示提供给云,则可额外获得 3 个奖励积分。您可以自己完成,也可以使用此模板- 这是一个 示例。这是有关如何使用它的视频。 代码质量通过且零错误 - 1 分 包括用于代码静态控制的代码质量 Github 操作,并使其显示 0 个 ObjectScript 错误。 关于开发者社区的文章 - 2 分 在 Developer Community 上发表一篇文章,描述您的项目的功能。每篇文章获得2分。不同语言的翻译也有效。 开发者社区第二篇文章 - 1分 您的第二篇文章或其应用的翻译文章可以获得额外的奖励积分。第 3 篇及以上不会带来更多积分,但文章和应用程序的关注度将全部归您所有。 上传 YouTube 视频 - 3 分 制作演示您的产品的 Youtube 视频,每个视频可获得 3 分奖励积分。例子。 首次贡献 - 3 分 如果您是第一次参加 InterSystems Open Exchange 竞赛,可获得 3 个奖励积分! 奖励积分清单可能会发生变化。敬请关注! 祝比赛好运!
公告
Claire Zheng · 一月 30

InterSystems 开发者社区2022年度调查

亲爱的开发者们, 非常感谢您又在 InterSystems 开发者社区度过了一年! 我们的团队日复一日地努力让它变得更好,这对我们12000+ 每一位成员都很重要! 我们想知道目前开发者社区对您有多大用处。请花点时间让我们了解您的想法,以及可以改进的地方: 👉🏼 InterSystems 开发者社区2022年度调查 👈🏼 请知悉:调查可在 5 分钟内完成。 也欢迎您在本文的评论部分提供反馈。 我们期待了解您的意见! 😉
公告
Michael Lei · 一月 23

InterSystems 开发者竞赛:Tool(工具)

嘿开发者, 我们想邀请您参加我们的下一场比赛,该比赛致力于创造有用的工具,让您的开发伙伴们的生活更轻松: 🏆 InterSystems 开发者竞赛:Tool(工具)🏆 提交有助于加快开发速度、贡献更多定性代码并有助于使用 InterSystems IRIS 测试、部署、支持或监控您的解决方案的应用程序。 时间: 2023 年 1 月 23 日至 2 月 12 日(美国东部时间) 奖金池: 13,500 美元 话题 💡 InterSystems IRIS 开发者竞赛:Tool(工具)💡 在本次竞赛中,我们期待应用程序能够改善开发人员使用 IRIS 的体验,帮助更快地开发,贡献更多定性代码,帮助测试、部署、支持或监控您使用 InterSystems IRIS 的解决方案。 一般要求: 已接受的应用程序:Open Exchange 应用程序或现有应用程序的新应用程序,但有显着改进。我们的团队将审核所有申请,然后再批准他们参加比赛。 该应用程序应该可以在InterSystems IRIS Community Edition上运行。 匹配的应用程序类型:UI 框架、IDE、数据库管理、监控、部署工具等。 该应用程序应该是开源应用程序并发布在 GitHub 上。 应用程序的自述文件应为英文,包含安装步骤,并包含视频演示或/和应用程序工作原理的描述。 一位开发者最多可以携带 3 个应用程序参加比赛。 奖品 1. 专家提名奖(Experts Nomination)- 获奖者由我们特别挑选的专家团选出:: 🥇第一名 - 5,000 美元 🥈第二名 - 3,000 美元 🥉第三名 - 1,500 美元 🏅第四名 - $750 🏅第五名 - $500 🌟第 6-10 名 - $100 2. 社区提名奖(Community Nomination)- 获得总投票数最多的应用: 🥇第一名 - $750 🥈第二名 - $500 🥉第三名 - $250 如果几个参与者获得相同数量的选票,他们都被认为是赢家,奖金由赢家分享。 重要截止日期: 🛠 应用开发和注册阶段: 2023 年 1 月 23 日(美国东部时间 00:00):比赛开始。 2023 年 2 月 5 日(美国东部时间 23:59):提交截止日期。 ✅ 投票时间: 2023 年 2 月 6 日(美国东部时间 00:00):投票开始。 2023 年 2 月 12 日(美国东部时间 23:59):投票结束。 注意:开发者可以在整个注册和投票期间改进他们的应用程序。 谁可以参加? 任何开发人员社区成员,InterSystems 员工除外。 创建一个帐户! 👥开发人员可以组队创建协作应用程序。一个团队允许 2 到 5 名开发人员。 不要忘记在应用程序的自述文件中突出显示您的团队成员——DC 用户配置文件。 有用的资源 ✓ 示例应用程序: iris-rad-studio - 用于 UI 的 RAD cmPurgeBackup - 备份工具 errors-global-analytics - 错误可视化 objectscript-openapi-definition - 开放 API 生成器 测试覆盖率工具- 测试覆盖率助手 还有更多。 ✓ 我们建议从以下模板开始: IRIS开发模板 rest-api-竞赛模板 本机 API 竞赛模板 IRIS FHIR模板 IRIS全栈模板 IRIS互操作性模板 IRIS分析模板 ✓ 对于 IRIS 初学者: 使用 InterSystems IRIS 构建服务器端应用程序 新手学习路径 ✓ 对于ObjectScript 包管理器 (ZPM)的初学者: 如何使用 InterSystems IRIS 的 REST 应用程序构建、测试和发布 ZPM 包 使用 InterSystems IRIS 和 ZPM 的封装优先开发方法 ✓ 如何提交您的应用程序参加比赛: 如何在 Open Exchange 上发布应用程序 如何提交比赛申请 需要帮忙? 加入 InterSystems 的Discord 服务器上的竞赛频道或在本文的评论中与我们交谈。 我们迫不及待地想看到您的项目!祝你好运👍 参加本次比赛,即表示您同意此处列出的比赛条款。请在继续之前仔细阅读它们。
文章
Michael Lei · 六月 7, 2022

InterSystems 最佳实践之--发挥 $Query 的最大作用

我今天遇到了一个有趣的ObjectScript用例,有一个通用的解决方案,我想与大家分享。 用例: 我有一个JSON数组(在本例中具体而言是一个来自Jira的问题数组),我想在几个字段上进行聚合--例如,类别、优先级和问题类型。然后,我想把聚合的数据编平化到一个简单的列表中,其中包含每个组的总数。当然,对于聚合来说,使用一个本地数组的形式是有意义的,即: agg(category, priority, type) = total 这样,对于输入数组中的每一条记录,我可以只用: Do $increment(agg(category, priority, type)) 但是一旦我做了聚合,我想把它变成一种更容易迭代的形式,比如一个整数下标的数组: summary = n summary(1) = $listbuild(total1, category1, priority1, type1) ... summary(n) = $listbuild(totalN, categoryN, priorityN, typeN) 基础解决方案: 简单的方法是,用$Order嵌套三个For循环--比如说: Set category = "" For { Set category = $Order(agg(category)) Quit:category="" Set priority = "" For { Set priority = $Order(agg(category,priority)) Quit:priority="" Set type = "" For { Set type = $Order(agg(category,priority,type),1,total) Quit:type="" Set summary($i(summary)) = $listbuild(total,category,priority,type) } } } 这就是我开始使用的方法,但它有很多代码,而且如果我有更多的维度来聚合,它很快就会变得不方便了。这让我想知道--是否有一个通用的解决方案来完成同样的事情?事实证明是有的! 使用 $Query的优化方案: 我决定使用$query会有帮助。请注意,这个解决方案假定整个本地数组中子标/值的深度是一致的;如果没有了这个假设,就会导致奇怪的结果. ClassMethod Flatten(ByRef deep, Output flat) [ PublicList = deep ] { Set reference = "deep" For { Set reference = $query(@reference) Quit:reference="" Set value = $listbuild(@reference) For i=1:1:$qlength(reference) { Set value = value_$listbuild($qsubscript(reference,i)) } Set flat($i(flat)) = value } } 所以以上片段被替换为: Do ..Flatten(.agg,.summary) 几点需要注意的: deep 需要在PublicList中,以便$query能够对其进行操作 在每个迭代中,reference 被改变为引用deep中下一组有价值的子标号--例如,值可能是:deep("foo", "bar") $qlength 返回reference中子标的数量 $qsubscript 返回reference中第i个下标的值 当$listbuild列表被串联起来时,一个有效的$listbuild列表与合并后的列表就得出结果(这比使用任何其他分隔符都要好!) 总结 $query, $qlength, 和 $qsubscript 在处理任意深度的Global/Local数组时非常方便。 进阶阅读 $Query: https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_FQUERY$QSubscript: https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.cls?KEY=RCOS_fqsubscript$QLength: https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.cls?KEY=RCOS_fqlength
文章
Jingwei Wang · 七月 29, 2022

InterSystems SQL 的优化 - 第一部分 - 定义和构建索引

什么时候使用索引 索引提供了一种机制,通过维护常用数据的分类子集来优化查询。确定哪些字段应该被编入索引需要一些思考:太少或错误的索引,关键查询会运行得太慢;太多的索引会减慢INSERT和UPDATE的性能(因为索引值必须被设置或更新)。 索引什么 为了确定添加索引是否能提高查询性能,从管理门户的SQL界面运行查询,并在Performance中注意 global引用的数量。添加索引,然后重新运行查询,注意 global引用的数量。一个有用的索引应该减少 global引用的数量。你可以通过使用%NOINDEX关键字作为WHERE子句或ON子句条件的前言来阻止索引的使用。 你应该对JOIN中指定的字段(属性)进行索引。例如,LEFT OUTER JOIN从左表开始,然后查看右表,因此,你应该对右表的字段进行索引。在下面的例子中,你应该为T2.f2编制索引。一个INNER JOIN应该在两个ON子句字段上都有索引。 FROM Table1 AS T1 LEFT OUTER JOIN Table2 AS T2 ON T1.f1 = T2.f2 如果查询计划中的第一个项目是 "read master map",或者查询计划调用的模块的第一个项目是 "read master map",那么查询的第一个map就是master map而不是索引map。因为主图读取的是数据本身,而不是数据的索引,这几乎总是表明一个低效的查询计划。除非该表相对较小,否则你应该创建一个索引,以便当你重新运行这个查询时,查询计划的第一张map显示 "read index map"。 你应该为WHERE子句中指定的相等条件的字段建立索引。 你可能希望为WHERE子句范围条件中指定的字段,以及GROUP BY和ORDER BY子句中指定的字段建立索引。 在某些情况下,基于范围条件的索引会使查询变慢。如果绝大多数的记录都满足指定的范围条件,就会出现这种情况。例如,如果查询子句WHERE Date < CURRENT_DATE被用于一个数据库,其中大部分记录来自以前的日期,在Date上建立索引实际上会降低查询速度。这是因为查询优化器假定范围条件将返回相对较少的行,并针对这种情况进行优化。你可以通过在范围条件前加上%NOINDEX来确定是否发生了这种情况,然后再次运行查询。 如果你使用一个索引字段进行比较,那么在比较中指定的字段应该具有和它在相应索引中相同的collation类型。例如,在SELECT的WHERE子句或JOIN的ON子句中的Name字段应该具有与为Name字段定义的索引相同的排序方式。如果字段的排序和索引的排序不匹配,那么索引的有效性就会降低,或者根本就不能使用。 在map中存储的表 一个SQL表被存储为一组map。每个表都有一个主图,包含了表中的所有数据;表还可能有其他图,如索引图和位图。每个map可以被想象成一个多维global,一些字段的数据在一个或多个子标中,其余字段存储在节点值中。这些子标控制着哪些数据被访问。 对于主映射,RowID或IDKEY字段通常被用作映射子标。 对于索引map,通常使用其他字段作为前导下标,RowID/IDKEY字段作为额外的低级下标。 对于一个位图,位图层可以被认为是一个额外的RowID下标层。然而,位图只能用于正整数的RowIDs。 Master Map 系统为每个表自动定义了一个主图(Data/Master)。master map不是一个索引,它是一个使用其map下标字段直接访问数据本身的map。默认情况下,主图的下标字段是系统定义的RowID字段。默认情况下,这种使用RowID字段的直接数据访问是用SQL map名称(SQL索引名称)IDKEY表示的。 默认情况下,一个用户定义的主键不是IDKEY。这是因为使用RowID整数的Master Map查询几乎总是比通过主键值查询更有效率。然而,如果你指定主键是IDKEY,主键索引就会被定义为表的主映射,SQL Map Name是主键SQL索引的名称。 对于一个单字段的主键/IDKEY,主键索引是Master Map,但是Master Map的数据访问列仍然是RowID。这是因为记录的唯一主键字段值和它的RowID值之间存在一对一的匹配,而且RowID被认为是更有效的查询。对于多字段主键/IDKEY,主映射被赋予主键索引名称,主映射的数据访问列是主键字段。 选择一个索引类型 下面是在位图索引和标准索引之间进行选择的一般指导原则: 一般来说,可以对这些类型使用标准索引:主键、外键、唯一键、关系、简单的对象引用。 否则,位图索引通常是比较好的(假设该表使用系统分配的数字ID号)。 其他因素:每个属性上的独立位图索引通常比多个属性上的位图索引有更好的性能。这是因为SQL引擎可以使用AND和OR操作有效地组合独立的位图索引。 如果一个属性(或一组你真正需要一起索引的属性)有超过10,000-20,000个不同的值(或值组合),请考虑标准索引。然而,如果这些值的分布非常不均匀,以至于少量的值占了相当一部分行,那么位图索引可能会好得多。一般来说,我们的目标是减少索引所需的总体大小。 定义和建立索引 以下是建立索引的原则: 你可以在表中的字段值上定义一个索引,或者在类中的相应属性上定义一个索引。 你也可以在几个字段/属性的组合值上定义一个索引。无论你是用SQL字段和表的语法,还是用类的属性语法来定义,都会创建相同的索引。 当某些类型的字段(属性)被定义时,InterSystems IRIS会自动定义索引,例如主键和唯一值属性。 你可以为同一个字段(属性)定义一个以上的索引,为不同的目的提供不同类型的索引。 每当对数据库进行数据插入、更新或删除操作时,InterSystems IRIS都会填充和维护索引(默认情况下),无论是使用SQL字段和表语法,还是使用类属性语法。你可以覆盖这个默认值(通过使用%NOINDEX关键字)来快速对数据进行修改,然后作为一个单独的操作建立或重建相应的索引。你可以在用数据填充一个表之前定义索引,你也可以为一个已经填充了数据的表定义索引,然后作为一个单独的操作填充(建立)索引。 InterSystems IRIS在准备和执行SQL查询时,会使用可用的索引。默认情况下,它选择使用哪些索引来优化查询性能。你可以覆盖这个默认值,以防止在特定的查询或所有的查询中使用一个或多个索引,视情况而定。 索引属性 每个索引都有一个唯一的名字。这个名称用于数据库管理目的(报告、建立索引、删除索引等等)。像其他SQL实体一样,一个索引也有一个SQL索引名和一个相应的索引属性名;这些名称在允许的字符、大小写敏感度和最大长度上有所不同。 如果使用SQL CREATE INDEX命令定义,系统会生成一个相应的索引属性名。如果使用持久化类定义,SqlName关键字允许用户指定一个不同的SQL索引名称(SQL映射名称)。管理门户SQL界面的目录详情显示了每个索引的SQL索引名称(SQL映射名称)和相应的索引属性名称(索引名称)。 索引类型是由两个索引类关键字Type和Extent定义的。InterSystems IRIS可用的索引类型包括: 标准索引(类型=索引)- 一个持久的数组,将索引值与包含该值的行的RowID联系起来。任何没有明确定义为位图索引、位片索引或范围索引的索引都是一个标准索引。 位图索引(类型=位图)--一种特殊的索引,它使用一系列的bitstring来表示对应于给定索引值的RowID值的集合;InterSystems IRIS包括一些针对位图索引的性能优化。 位片索引(类型=位片)--一种特殊的索引,能够非常快速地评估某些表达式,如sum范围条件。某些SQL查询会自动使用位片索引。 Extent Indices(位图范围索) - 一个范围内所有对象的索引。 一个表(类)的最大索引数是400。 系统自动定义的索引 当你定义一个表时,系统会自动定义某些索引。以下索引在你定义表时自动生成,并在你添加或修改表数据时被填充。如果你定义了: 一个不是IDKEY的主键,系统会生成一个Unique类型的相应索引。主键索引的名称可以是用户指定的,也可以是从表的名称中衍生出来的。例如,如果你定义了一个未命名的主键,相应的索引将被命名为tablenamePKEY#,其中#是每个唯一键和主键约束的一个连续的整数。 一个UNIQUE字段,InterSystems IRIS为每个UNIQUE字段生成一个索引,名称为tablameUNIQUE#,其中#是每个唯一键和主键约束的连续整数。 一个UNIQUE约束,系统为每个具有指定名称的UNIQUE约束生成一个索引,为共同定义一个唯一值的字段生成索引。 一个分片Shard Key,系统为分片键字段生成一个索引,名为ShardKey。 你可以通过管理门户的SQL目录细节标签查看这些索引。CREATE INDEX命令可以用来添加一个UNIQUE字段约束;DROP INDEX命令可以用来删除一个UNIQUE字段约束。 默认情况下,系统会在RowID字段上生成IDKEY索引。定义一个IDENTITY字段并不产生索引。然而,如果你定义了一个IDENTITY字段并使该字段成为主键,InterSystems IRIS会在IDENTITY字段上定义IDKEY索引并使其成为主键索引。这在下面的例子中显示。 CREATE TABLE Sample.MyStudents ( FirstName VARCHAR(12), LastName VARCHAR(12), StudentID IDENTITY, CONSTRAINT StudentPK PRIMARY KEY (StudentID) ) 同样,如果你定义了一个IDENTITY字段,并给该字段一个UNIQUE约束,InterSystems IRIS会明确地在IDENTITY字段上定义一个IdKey/Unique索引。这在下面的例子中显示。 CREATE TABLE Sample.MyStudents ( FirstName VARCHAR(12), LastName VARCHAR(12), StudentID IDENTITY, CONSTRAINT StudentU UNIQUE (StudentID) ) 这些IDENTITY索引操作只在没有明确定义的IdKey索引和表不包含数据的情况下发生。 手动定义索引 有两种方法来定义索引。 使用类定义来定义索引,其中包括: 可以被索引的属性 多个属性的索引 索引的整理 在索引中使用Unique、PrimaryKey和IdKey关键字 定义SQL搜索索引 用索引存储数据 对NULL进行索引 索引集合 阵列集合的索引 用(ELEMENTS)和(KEYS)对数据类型属性进行索引 为嵌入式对象(%SerialObject)属性建立索引 关于在类中定义的索引的说明 使用DDL定义索引 使用类定义来定义索引 Class MyApp.Student Extends %Persistent [DdlAllowed] { Property Prop1 As %String; Property Prop2 As %String; //单一属性定义索引 Index Prop1IDX On Prop1; //多属性值定义索引 Index MIXIDX On (Prop1, Prop2) //使用单一属性和collation定义索引 Index Prop2IDX On Prop2 As Exact; //使用多属性和collation定义索引 Index MIX2IDX On (Prop1 As SQLUPPER,Prop2 As Exact); //使用Unique关键字定义索引 Index Prop1IDX On Prop1 [Unique] //使用PrimaryKey关键字定义索引 Index Prop1IDX On Prop1 [PrimaryKey] //使用IdKey关键字定义索引 Index Prop1IDX On Prop1 [IdKey] //定义查询索引 -- 供文档查询使用 Index Prop1IDX On (Prop1) As %iFind.Index.Basic //List或者Array属性定义索引 Index EmpIndex On Employees(KEYS) Index EmpIndex On Employees(ELEMENTS) Index EmpIndex On (Employees(KEYS), Employees(ELEMENTS)); //对象属性定义索引 Index StateInx On Home.State; //定义位图索引 Index ReginIDX On Region [Type = bitmap] //定义位片索引 Index AgeIDX On Age [Type = bitslice] } 在类定义中处理索引时,有几点需要注意: 索引定义只从主(第一)超类中继承。 如果你使用Studio为一个有数据存储的类添加(或删除)一个索引定义,你必须通过构建索引来手动填充索引。 使用类定义定义%BID位图索引 如果表的ID不是正整数,你可以创建一个%BID属性,用来创建位图索引定义。你可以对具有任何数据类型的ID字段的表,以及由多个字段组成的IDKEY(其中包括子表)使用这个选项。可以为任一数据存储类型创建%BID位图:默认结构表或%Storage.SQL表。这个功能被称为 "任何表的位图Bitmaps for Any Table",或BAT。 要在这样的表中启用位图索引,你必须做以下工作。 为该类定义一个%BID属性/字段。这可以是该类的一个现有属性,也可以是一个新的属性。它可以有任何名字。如果这是一个新的属性,你必须为表中的所有现有行填充这个属性/字段。这个%BID字段必须用一个数据类型来定义,限制字段数据值为唯一的正整数。例如: Property MyBID As %Counter; 定义一个新的类参数来定义哪个属性是%BID字段。这个参数被命名为BIDField。这个参数被设置为%BID属性的SQLFieldName。例如,参数BIDField = "MyBID"。 Parameter BIDField = "MyBID"; 为%BID定义一个索引。例如, Index BIDIdx On MyBID [ Type = key, Unique ] 。 定义%BID定位器索引。这将%BID索引与表的ID关键字段联系起来。下面的例子是关于一个有两个字段组成的复合IDKey的表。 Index IDIdx On (IDfield1, IDfield2) [ IdKey, Unique ] 。 Index BIDLocIdx On (IDfield1, IDfield2, MyBID) [ Data = IdKey, Unique ] 。 这个表现在支持位图索引。你可以使用标准语法根据需要定义位图索引。例如: Index RegionIDX On Region [Type = bitmap] 该表现在也支持位片索引。你可以使用标准语法定义位片索引。 注意: 要建立或重建一个%BID位图索引,你必须使用%BuildIndices()。%ConstructIndicesParallel()方法不支持%BID位图索引。 使用DDL定义索引 DDL索引命令做了以下工作。 它们更新相应的类和表的定义,在这些定义上添加或删除索引。修改后的类定义被重新编译。 它们根据需要在数据库中添加或删除索引数据。CREATE INDEX命令使用当前存储在数据库中的数据来填充索引。同样,DROP INDEX命令从数据库中删除了索引数据(也就是实际的索引)。 CREATE INDEX //标准索引 CREATE INDEX StateIdx ON TABLE Sample.Person (Home_State) ​ //位图范围索引 CREATE BITMAPEXTENT INDEX Patient ON TABLE Sample.Patient ​ //位图索引 CREATE BITMAP INDEX RegionIDX ON TABLE MyApp.SalesPerson (Region) ​ //位片索引 CREATE BITSLICE INDEX AgeIDX ON TABLE MyApp.SalesPerson (Age) ​ DROP INDEX DROP INDEX PeopleIndex ON TABLE Employee 为嵌入式对象(%SerialObject)属性创建索引 要为嵌入式对象中的一个属性建立索引,你要在引用该嵌入式对象的持久化类中创建一个索引。属性名必须指定表(%Persistent类)中的引用字段的名称和嵌入对象(%SerialObject)中的属性,如下面的例子所示。 Class Sample.Person Extends (%Persistent) [ DdlAllowed ] { Property Name As %String(MAXLEN=50); Property Home As Sample.Address; Index StateInx On Home.State; } 这里Home是Sample.Person中的一个属性,它引用嵌入式对象Sample.Address,其中包含State属性,如下例所示。 Class Sample.Address Extends (%SerialObject) { Property Street As %String; Property City As %String; Property State As %String; Property PostalCode As %String; } 只有与持久化类属性引用相关的嵌入式对象实例中的数据值被索引。你不能直接索引%SerialObject属性。%Library.SerialObject(以及所有没有明确定义SqlCategory的%SerialObject的子类)的SqlCategory是STRING。 你也可以使用SQL CREATE INDEX语句在嵌入式对象属性上定义一个索引,如下面的例子所示。 CREATE INDEX StateIdx ON TABLE Sample.Person (Home_State) 位图索引 位图索引是一种特殊类型的索引,它使用一系列的bit字符串来表示与给定的索引数据值相对应的ID值集合。 位图索引有以下重要特点: 位图是高度压缩的:位图索引可以比标准索引小得多。这大大减少了磁盘和缓存的使用。 位图操作为事务处理进行了优化:你可以在表内使用位图索引,与使用标准索引相比,没有性能损失。 位图上的逻辑操作(计数、和、以及OR)被优化为高性能。 SQL引擎包括一些特殊的优化,可以利用位图索引的优势。 位图索引的创建取决于表的唯一标识字段的性质。 如果表的ID字段被定义为一个具有正整数值的单一字段,你可以使用这个ID字段为一个字段定义位图索引。这种类型的表要么使用系统分配的唯一正整数ID,要么使用IdKey定义自定义ID值,其中IdKey基于类型为%Integer且MINVAL>0的单一属性,或类型为%Numeric且SCALE=0且MINVAL>0的单一属性。 如果表的ID字段没有定义为具有正整数值的单一字段(例如,一个子表),你可以定义一个%BID(位图ID)字段,它采取正整数,作为一个代理ID字段;这允许你为这个表中的字段创建位图索引。 本章讨论了与位图索引有关的下列主题“ 位图索引操作 通过使用类定义来定义位图索引 使用DDL定义位图索引 生成一个位图范围索引 选择一个索引类型 对位图索引的限制 维护位图索引 位图分块的SQL操作 位图索引操作原理 位图索引的工作方式如下。假设你有一个包含若干列的Person表,这个表中的每一行都有一个系统分配的RowID号码(一组递增的整数值)。一个位图索引使用一组bitstring(一个包含1和0值的字符串)。在一个bitstring内,一个bit的序号位置对应于被索引表的RowID。对于一个给定的值,例如State是 "NY",有一个bitstring,对应于包含 "NY "的行,每个位置都是1,其他不包含'NY'的行,位置都是0。 例如,一个关于State的位图索引可能看起来像这样: 而关于年龄的索引可能看起来像这样。 注意: 这里显示的年龄字段可以是一个普通的数据字段,也可以是一个可以靠其他字段得出的字段(计算和SQLComputed)。 除了在标准操作中使用位图索引外,SQL引擎还可以使用位图索引,使用多个索引的组合有效地执行基于集合的特殊操作。例如,为了找到所有24岁并居住在纽约的Person实例,SQL引擎可以简单地执行Age和State索引的 AND 逻辑。结果如下: SQL引擎可以使用位图索引进行以下操作: 在一个给定的表上对多个条件进行ANDing。 在一个给定的表上的多个条件的ORing。 在一个给定的表上的RANGE条件。 在一个给定的表上进行COUNT操作。 位图索引的限制 所有的位图索引都有以下限制: 不能在一个UNIQUE列上定义一个位图索引。 不能在位图索引中存储数据值。 不能在一个字段上定义位图索引,除非该字段的SqlCategory是INTEGER, DATE, POSIXTIME, 或NUMERIC (with scale=0) 。 对于一个包含超过100万条记录的表来说,当唯一值的数量超过10,000时,位图索引的效率就不如标准索引。因此,对于一个大表,建议你避免对任何包含(或可能包含)超过10,000个唯一值的字段使用位图索引;对于任何规模的表,避免对任何可能包含超过20,000个唯一值的字段使用位图索引。这些都是一般的近似值,不是精确的数字。 你必须创建一个%BID属性来支持表上的位图索引,该表 使用一个非整数字段作为唯一的ID键。 使用一个多字段的ID键。 是父-子关系中的一个子表。 你可以使用$SYSTEM.SQL.Util.SetOption()方法SET status=$SYSTEM.SQL.Util.SetOption("BitmapFriendlyCheck",1,.oldval)来设置一个系统范围的配置参数,在编译时检查这个限制,确定%Storage.SQL类中是否允许定义位图索引。这个检查只适用于使用%Storage.SQL的类。你可以使用$SYSTEM.SQL.Util.GetOption("BitmapFriendlyCheck")来确定这个选项的当前配置。 应用逻辑的限制: 一个位图结构可以用一个bitstring数组来表示,其中数组的每个元素代表一个具有固定bit数的 "块"。因为未定义等同于一个全部为0位的块,所以数组可以是稀疏的。一个代表所有0 bit的块的数组元素根本就不需要存在。由于这个原因,应用逻辑应该避免依赖0值位的$BITCOUNT(str,0)计数。 因为一个bitstring包含内部格式化,应用逻辑不应该依赖于一个bitstring的物理长度,也不应该依赖于对两个具有相同位值的bitstring进行等价。在回滚操作之后,一个bitstring被恢复到事务之前的位值。然而,由于内部格式化,回滚的bitstring可能不等同于事务之前的bitstring,也不具有相同的物理长度。 维护位图索引 在一个不稳定的表(一个经历了许多INSERT和DELETE操作的表),位图索引的存储可能会逐渐变得不那么有效。 为了维护位图索引,你可以运行%SYS.Maint.Bitmap工具方法来压缩位图索引,将其恢复到最佳效率。你可以使用OneClass()方法来压缩单个类的位图索引。或者你可以使用Namespace()方法来压缩整个命名空间的位图索引。这些维护方法可以在一个生产系统上运行。 d ##class(%SYS.Maint.Bitmap).Namespace("Samples",1,1,"2014-01-17 09:00:00") d ##class(%SYS.Maint.Bitmap).OneClass("BitMap.Test",1,1) 运行%SYS.Maint.Bitmap实用方法的结果被写到调用该方法的进程中。这些结果也被写入%SYS.Maint.BitmapResults类中。 位片索引 当一个数字数据字段被用于某些数字操作时,位片索引被用于该字段。位片索引将每个数字数据值表示为一个二进制位串。比起使用布尔标志对数字数据值进行索引(如在位图索引中),位片索引用二进制表示每个值,并为二进制值中的每个数字创建一个位图来记录哪些行的二进制数字为1。这是一种高度专业化的索引类型,可以大幅度提高以下操作的性能。位片索引适用于以下类型: SUM, COUNT, 或AVG聚合计算。(位片索引不用于COUNT(*)计算) 位片索引不用于其他聚合函数。 在 TOP n ... ORDER BY field 的操作。 在一个范围条件操作中指定的字段,例如 WHERE field > n or WHERE field BETWEEN lownum AND highnum SQL优化器决定是否应该使用定义的位片索引。通常情况下,优化器只在处理大量的行(成千上万)时才使用位片索引。 在一个不稳定的表(一个经历了许多INSERT、UPDATE和DELETE操作的表)中,位片索引的存储效率会逐渐降低。%SYS.Maint.Bitmap工具方法同时压缩了位图索引和位片索引,恢复了效率。更多细节,请看 "维护位图索引"。 位图范围索引 位图范围索引是针对表的行的位图索引,而不是针对表的任何指定字段。在位图范围索引中,每个位代表一个连续的RowID整数值,每个位的值指定相应的行是否存在。InterSystems SQL使用这种索引来提高COUNT()的性能,COUNT()返回表中的记录数(行数)。一个表最多可以有一个位图范围索引。试图创建一个以上的位图范围索引,会导致SQLCODE -400错误,并出现%msg ERROR #5445: 定义了多个范围索引。 一个位图索引需要一个位图范围索引。只有在定义了一个或多个位图索引的情况下,定义一个持久化类才会生成一个位图范围索引。因此,当编译一个包含位图索引的持久化类时,如果没有为该类定义位图范围索引,类编译器会生成一个位图范围索引。 如果你从持久化类定义中删除了所有位图索引,那么位图范围索引会自动删除。但是,如果你重命名位图范围索引(例如,使用CREATE BITMAPEXTENT INDEX命令),删除位图索引并不会删除位图范围索引。 当为一个类建立索引时,如果你明确地建立了位图范围索引,或者你建立了位图索引而位图范围索引是空的,那么位图范围索引就会被建立。 一个类从主超类继承它的位图范围索引,如果它存在的话,可以定义或生成。一个位图范围索引被定义为:type = bitmap, extent = true。这意味着从主超类继承的位图范围索引被认为是一个位图索引,如果在子类中没有明确定义位图范围索引,则会触发在子类中生成一个位图范围索引。 InterSystems IRIS不会根据未来的可能性在超类中生成一个位图范围索引。这意味着InterSystems IRIS永远不会在一个持久性类中生成一个位图范围索引,除非有一个类型=位图的索引存在。假设某个未来的子类可能引入一个类型=位图的索引是不够的。 注意:在生产系统上为一个类添加位图索引的过程中需要特别注意(当用户使用一个特定的类,编译该类,并随后为它建立位图索引结构)。在这样的系统上,位图范围索引可能会在编译完成和索引建立过程的中间阶段被填充。这可能导致索引构建程序没有隐含地构建位图范围索引,这导致了部分位图范围索引不能被构建。 在一个经历了许多DELETE操作的表中,位图范围索引的存储会逐渐变得不那么有效。你可以通过使用BUILD INDEX命令重建位图范围索引,或者从管理门户选择表的Catalog Details标签,Maps/Indices选项并选择Rebuild Index。 构建索引 构建一个索引会做以下事情。 移除索引的当前内容。 扫描(读取每一行)主表,为表中的每一行添加索引条目。如果可能的话,使用特殊的$SortBegin和$SortEnd函数来确保建立大型索引的效率。当建立标准索引时,除了在内存中缓存数据外,这种对$SortBegin/$SortEnd的使用会占用IRISTEMP数据库的空间。因此,当建立一个非常大的标准索引时,InterSystems IRIS可能需要IRISTEMP中的空间,大致相当于最终索引的大小。 注意:建立索引的方法只提供给使用InterSystems IRIS默认存储结构的类(表)。 当前的数据库访问决定了你应该如何重建一个现有的索引: 非活跃系统(在索引建立或重建期间没有其他进程访问数据) 只读活跃系统(其他进程在索引建立或重建期间能够查询数据) 读和写活跃系统(其他进程能够修改数据,并在索引建立或重建期间查询数据)。 你可以按以下方式建立/重新建立索引。 使用BUILD INDEX SQL命令来构建指定的索引,或构建为一个表、一个Schema或当前命名空间定义的所有索引: //为整个表构建索引 BUILD INDEX FOR TABLE table-name //为一个Schema下的所有表构建索引 BUILD INDEX FOR SCHEMA schema-name //为整个命名空间构建索引 BUILD INDEX FOR ALL 使用管理门户为一个指定的类(表)重建所有的索引。 系统资源管理器 - SQL- 操作 - 重建表索引 使用%BuildIndices()(或%BuildIndicesAsync())方法,如本节所述。 建立索引的首选方法是使用%BuildIndices()方法或%BuildIndicesAsync()方法。 %Library.Persistent.%BuildIndices()。%BuildIndices()作为一个后台进程执行,但调用者必须等待%BuildIndices()完成后才能接收控制权。 %Library.Persistent.%BuildIndicesAsync()。BuildIndicesAsync()将%BuildIndices()作为一个后台进程启动,调用者立即收到控制权。%BuildIndicesAsync()的第一个参数是queueToken输出参数。其余的参数与%BuildIndices()相同。 %BuildIndicesAsync()返回一个%Status值:成功表示%BuildIndices()工作任务成功排队;失败表示工作任务没有成功排队。 %BuildIndicesAsync()向queueToken输出参数返回一个值,表示%BuildIndices()完成状态。为了获得完成状态,你通过引用queueToken值传递给%BuildIndicesAsyncResponse()方法。你还指定了wait布尔值。如果wait=1,%BuildIndicesAsyncResponse()将等待,直到由queueToken识别的%BuildIndices()作业完成。如果wait=0,%BuildIndicesAsyncResponse()将尽可能快地返回一个状态值。如果%BuildIndicesAsyncResponse()的queueToken在返回时不是NULL,那么%BuildIndices()作业还未完成。在这种情况下,queueToken可以用来再次调用%BuildIndicesAsyncResponse()。当%BuildIndicesAsyncResponse()的queueToken最终为空时,那么%BuildIndicesAsyncResponse()返回的%Status值就是由%BuildIndicesAsync()调用的作业的完成状态。 在一个不活跃的系统上构建索引: 系统自动生成方法(由%Persistent类提供),用于构建(即为其提供数值)或清除(即为其移除数值)为类(表)定义的每个索引。你可以通过以下两种方式使用这些方法。 通过管理门户: 系统资源管理器 - SQL- 操作 - 重建表索引 注意:当其他用户正在访问该表的数据时,不要重建索引。要在一个活跃系统上重建索引,请看在活跃系统上建立索引。 以编程方式调用。 构建所有索引:调用%BuildIndices(),没有参数,为给定的类(表)构建(提供)所有索引。 SET sc = ##class(MyApp.SalesPerson).%BuildIndices() IF sc=1 {WRITE !, "Successful index build" } ELSE {WRITE !, "Index build failed",! DO $System.Status.DisplayError(sc) QUIT} 构建指定的索引:调用%BuildIndices(),以$List的索引名称作为第一个参数,为一个给定的类(表)建立(提供)指定的索引。 SET sc = ##class(MyApp.SalesPerson).%BuildIndices($ListBuild("NameIDX", "SSNKey")) IF sc=1 {WRITE !, "Successful index build" } ELSE {WRITE !, "Index build failed",! DO $System.Status.DisplayError(sc) QUIT} 构建所有索引,除了某些指定索引:调用%BuildIndices(),将$List的索引名称作为第七个参数,为一个给定的类(表)构建(提供值)所有定义的索引,除了指定的索引。 SET sc = ##class(MyApp.SalesPerson).%BuildIndices("",,,,,,$ListBuild("NameIDX", "SSNKey")) IF sc=1 {WRITE !, "Successful index build" } ELSE {WRITE !"Index build failed",! DO $System.Status.DisplayError(sc) QUIT} %BuildIndices()方法做了以下工作: 在任何要重建的(非位图)索引上调用$SortBegin函数(这将为这些索引启动一个高性能的排序操作)。 循环处理该类的主要数据(表),收集索引使用的值,并将这些值添加到索引中(有适当的整理转换)。 调用$SortEnd函数来完成对索引的排序过程。 如果索引已经有了值,你必须用两个参数调用%BuildIndices(),其中第二个参数的值为1,为这个参数指定1会使该方法在重建索引之前清除这些值。比如说: SET sc = ##class(MyApp.SalesPerson).%BuildIndices(,1) IF sc=1 {WRITE !, "Successful index build" } ELSE {WRITE !, "Index build failed",! DO $System.Status.DisplayError(sc) QUIT} 这就清除并重建了所有的索引。你也可以清除和重建索引的一个子集,如: SET sc = ##class(MyApp.SalesPerson).%BuildIndices($ListBuild("NameIDX", "SSNKey"),1) IF sc=1 {WRITE !, "Successful index build" } ELSE {WRITE !, "Index build failed",! DO $System.Status.DisplayError(sc) QUIT} 注意:当其他用户正在访问该表的数据时,不要重建索引。要在一个活跃系统上重建索引,请看在活跃系统上建立索引。 在活跃系统上建立索引 当在一个活跃系统上建立(或重建)索引时,有两个问题: 活跃查询可能会返回不正确的结果,除非正在建立的索引被隐藏在SELECT查询之外。在建立索引之前,可以使用SetMapSelectability()方法来处理这个问题。 在建立索引期间对数据的主动更新可能不会反映在索引条目中。这可以通过在构建索引时让构建操作锁定个别行来处理。 注意:如果一个应用程序在一个事务中对数据进行大量的更新,可能会出现锁表争夺的问题。 在一个只读活跃系统上构建索引 如果一个表目前只用于查询操作(只读),你可以在不中断查询操作的情况下建立新的索引或重建现有索引。这是通过在重建这些索引时使索引对查询优化器不可用来实现的。 如果你想建立一个或多个索引的所有类目前都是只读的,使用 "在读和写活跃系统上建立索引 "中描述的相同系列操作,但有以下区别:当你使用%BuildIndices()时,设置pLockFlag=3(共享范围锁)。 在读和写活跃系统上建立索引 如果一个持久化的类(表)目前正在使用,并且可以进行读和写访问(查询和数据修改),你可以建立新的索引或者重建现有的索引而不中断这些操作。如果你想重建一个或多个索引的类目前可以被读和写访问,建立索引的首选方法是使用表的持久化类提供的%BuildIndices()(或%BuildIndicesAsync())方法。 在并发的读和写访问中,建立一个或多个索引需要进行以下一系列操作: 使你希望建立的索引对查询不可用(READ访问)。这是用SetMapSelectability()完成的。这使得该索引不能被查询优化器使用。这个操作应该在重建一个现有的索引和创建一个新的索引时执行。比如说 SET status=$SYSTEM.SQL.Util.SetMapSelectability("Sample.MyStudents", "StudentNameIDX",0) 第一个参数是Schema.Table名称,即SqlTableName,而不是持久化类的名称。例如,默认的Schema是SQLUser,而不是User。这个值是区分大小写的。 第二个参数是SQL索引图名称。这通常是索引的名称,指的是索引存储在磁盘上的名称。对于一个新的索引,这是你在创建索引时要使用的名称。这个值是不区分大小写的。 第三个参数是MapSelectability标志,其中0定义索引图为不可选择(关闭),1定义索引图为可选择(打开)。指定为0。 你可以通过调用GetMapSelectability()方法来确定一个索引是否是不可选择的。如果你已经明确地将一个索引标记为不可选择,这个方法返回0。在所有其他情况下,它返回1;它不对表或索引的存在进行验证检查。注意,Schema.Table名称是SqlTableName,并且区分大小写。 SetMapSelectability()和GetMapSelectability()仅适用于当前命名空间的索引映射。如果该表被映射到多个命名空间,并且需要在每个命名空间建立索引,则应在每个命名空间调用SetMapSelectability()。 在索引建立的过程中建立并发操作。 对于一个新的索引 在类中创建索引定义(或者在类的%Storage.SQL中创建新的SQL索引映射规范),编译该类。对于一个新的索引,这是合适的,因为索引还没有被填充。在可以对表进行查询之前,需要对范围索引进行填充。 对于一个现有的索引。清除任何引用该表的缓存查询。索引构建所执行的第一个操作是杀死索引。因此,当索引被重建时,你不能依靠任何被优化的代码来使用该索引。 //删除当前命名空间的所有缓存查询 PURGE CACHED QUERIES ​ //删除当前命名空间n天内的所有缓存查询 PURGE CACHED QUERIES BY AGE n Do $SYSTEM.SQL.Purge(n) ​ //删除某个表的缓存查询 PURGE CACHED QUERIES BY TABLE table-name 或者 Do $SYSTEM.SQL.PurgeForTable("MedLab.Patient") ​ //删除当类的缓存查询 PURGE [CACHED] QUERIES BY NAME class-name 使用你的持久化类(表)的%BuildIndices()方法,使用pLockFlag=2(行级锁)来建立索引。pLockFlag=2标志在重建过程中对个别行建立了一个排他性的写锁,这样并发的数据修改操作就可以与构建索引操作相协调。 默认情况下,%BuildIndices()会构建所有为持久化类定义的索引;你可以使用pIgnoreIndexList来排除重建索引。 默认情况下,%BuildIndices()为所有ID建立索引条目。然而,你可以你可以使用pStartID和pEndID来定义一个ID的范围。%BuildIndices()将只为该范围内的ID建立索引条目。例如,如果你使用带有%NOINDEX限制的INSERT将一系列新记录添加到表中,你可以随后使用带有ID范围的%BuildIndices()来为这些新记录建立索引条目。 %BuildIndices()返回一个%Status值。如果%BuildIndices()由于检索数据的问题而失败,系统会产生一个SQLCODE错误和一个消息(%msg),其中包括遇到错误的%ROWID。 一旦你完成了建立索引,请启用查询优化器的MapSelectability。设置第三个参数,MapSelectability标志为1,如下面的例子所示。 SET status=$SYSTEM.SQL.Util.SetMapSelectability("Sample.MyStudents", "StudentNameIDX",1) 再一次,清除任何引用该表的缓存查询。这将消除在此过程中创建的无法使用索引的缓存查询,因此,与使用索引的相同查询相比,缓存查询的效果较差。 这样就完成了这个过程。索引被完全填充,并且查询优化器能够考虑该索引。 注意:%BuildIndices()只能用于为有正整数ID值的表重建索引。如果父表有正的整数ID值,你也可以使用%BuildIndices()来重建子表的索引。对于其他表,使用%ValidateIndices()方法。因为%ValidateIndices()是建立索引的最慢的方法,所以只有在没有其他选择的情况下才应该使用它。 验证索引 你可以使用以下任一方法来验证索引: $SYSTEM.OBJ.ValidateIndices()验证一个表的索引,同时也验证该表的集合子表的任何索引。 %Library.Storage.%ValidateIndices()验证一个表的索引。集合子表的索引必须用单独的%ValidateIndices()调用进行验证。 这两种方法都检查指定表的一个或多个索引的数据完整性,并可选择纠正发现的任何索引完整性问题。它们分两步进行索引验证。 确认为表(类)中的每一行(对象)正确定义了一个索引实体。 遍历每个索引,对于每个被索引的条目,确保在表(类)中有一个值和匹配的条目。 如果任何一种方法发现不一致的地方,它可以选择性地纠正索引结构和内容。它可以验证并选择性地纠正标准索引、位图索引、位图范围索引和位片索引。默认情况下,这两个方法都验证索引,但不纠正索引。 只有在遵循以下条件的情况下,%ValidateIndices()才能用于纠正(建立)读和写活跃系统中的索引: SetMapSelectability()被使用,如上所述;%ValidateIndices()参数必须包括autoCorrect=1和lockOption>0。 因为%ValidateIndices()的速度明显较慢,%BuildIndices()是在活跃系统上建立索引的首选方法。 %ValidateIndices()通常从终端运行。它显示输出到当前设备。这个方法可以应用于指定的%List索引名称,或者为指定表(类)定义的所有索引。它只对那些起源于指定类的索引进行操作;如果一个索引起源于一个超类,该索引可以通过在超类上调用%ValidateIndices()进行验证。 只读类不支持%ValidateIndices()。 %ValidateIndices()被支持用于分片类和分片主类表(Sharded=1)。你可以调用%ValidateIndices,要么直接作为一个类方法,要么从$SYSTEM.OBJ.ValidateIndices上调用分片主类。然后在每个分片上的分片本地类上执行索引验证,并将结果返回给分片主类上的调用者。当在分片类上使用%ValidateIndices()时,verbose标志被强制为0,没有输出到当前设备。任何发现/纠正的问题都会在byreference errors()数组中返回。 下面的例子使用%ValidateIndices()来验证和纠正Sample.Person表的所有索引: SET status=##class(Sample.Person).%ValidateIndices("",1,2,1) IF status=1 {WRITE !, "Successful index validation/correction" } ELSE {WRITE !, "Index validation/correction failed",! DO $System.Status.DisplayError(status) QUIT}。 第一个参数("")指定要验证所有的索引; 第二个参数(1)指定要修正索引差异; 第三个参数(2)指定要对整个表进行独占锁定; 第四个参数(1)指定使用多个进程(如果有的话)来执行验证。该方法返回一个%Status值。 通过名称验证索引: SET IndList=$LISTBUILD("NameIDX", "SSNKey") SET status=##class(Sample.Person).%ValidateIndices(IndList,1,2,1) IF status=1 {WRITE !, "Successful index validation/correction" } ELSE {WRITE !, "Index validation/correction failed",! DO $System.Status.DisplayError(status) QUIT}。 %ValidateIndices()的第一个参数或$SYSTEM.OBJ.ValidateIndices()的第二个参数指定哪些索引将作为%List结构被验证。不管第一个参数的值如何,IdKey索引总是被验证的。你可以通过指定一个空字符串值("")来验证表的所有索引。你可以通过指定一个列表结构来验证该表的单个索引。下面的例子验证了IdKey索引和两个指定的索引。NameIDX和SSNKey。 对于这两种方法,如果索引列表包含一个不存在的索引名称,该方法不执行索引验证,并返回%Status错误。如果索引列表中包含一个重复的有效索引名称,该方法将验证指定的索引,忽略重复的索引,不发出错误。 索引信息查询 INFORMATION.SCHEMA.INDEXES持久化类显示当前命名空间中所有列索引的信息。它为每个被索引的列返回一条记录。它提供了一些索引的属性,包括索引的名称,表的名称,以及索引所对应的列的名称。每条列记录还提供了该列在索引图中的序号位置;除非索引映射到多个列,否则这个值是1。它还提供了布尔属性PRIMARYKEY和NONUNIQUE(0=索引值必须是唯一的)。 SELECT Index_Name,Table_Schema,Table_Name,Column_Name,Ordinal_Position, Primary_Key,Non_Unique FROM INFORMATION_SCHEMA.INDEXES WHERE NOT Table_Schema %STARTSWITH '%' 你可以使用管理界面的目录详情的映射/索引选项列出所选表的索引。这将为每个索引显示一行,并显INFORMATION.SCHEMA.INDEXES没有提供的索引信息。 使用索引对一个对象进行open、exist和delete的方法 InterSystems IRIS的索引支持以下操作: 通过索引键打开一个实例 检查一个实例是否存在 删除一个实例 通过索引key打开一个实例 对于ID键、主键或唯一索引,indexnameOpen()方法(其中indexname是索引的名称)允许你打开其索引属性值与所提供的值一致的对象。 例如,假设一个类包括下面的索引定义。 Index SSNKey On SSN [ Unique ] 。 那么,如果被引用的对象已经被存储到磁盘,并且有一个唯一的ID值,你可以按以下方式调用该方法。 SET person = ##class(Sample.Person).SSNKeyOpen("111-22-3333",2,.sc) 第一个参数对应于索引中的属性。 第二个参数指定要打开对象的并发值(这里是2 - 共享锁)。 第三个参数可以接受%Status代码,以防该方法无法打开一个实例,如果找到一个匹配的实例,该方法会返回一个OREF。如果该方法没有找到一个与所提供的值相匹配的对象,那么一个错误信息将被写入状态参数sc中。 这个方法被实现为%Compiler.Type.Index.Open()方法;这个方法类似于%Persistent.Open()和%Persistent.OpenId()方法,除了它使用索引定义中的属性而不是OID或ID参数。 检查一个对象是否存在 indexnameExists()方法(其中indexname是索引的名称)检查是否存在一个具有该方法的参数所指定的索引属性值的实例。该方法有一个参数对应于索引中的每个属性;它的最后一个可选参数可以接收对象的ID,如果有一个与提供的值相匹配的话。该方法返回一个布尔值,表示成功(1)或失败(0)。这个方法被实现为%Compiler.Type.Index.Exists()方法。 例如,假设一个类包括下面的索引定义。 Index SSNKey On SSN [ Unique ]; 那么,如果被引用的对象已经被存储到磁盘,并且有一个唯一的ID值,你可以按以下方式调用该方法。 SET success = ##class(Sample.Person).SSNKeyExists("111-22-3333",.id) 成功完成后,success等于1,id包含与找到的对象匹配的ID。 该方法返回所有索引的值,除了。 位图索引,或位图范围索引。 当索引包括(ELEMENTS)或(KEYS)表达式时。 删除一个对象 indexnameDelete()方法(其中indexname是索引的名称)是为了与Unique、PrimaryKey和/或IdKey索引一起使用;它删除其键值与提供的键属性/列值相匹配的实例。有一个可选的参数,你可以用它来指定该操作的并发设置。该方法返回一个%Status代码。它被实现为%Compiler.Type.Index.Delete()方法。
文章
Jingwei Wang · 七月 14, 2022

InterSystems SQL 的使用 - 第二部分 - 基础介绍

本文概述了InterSystems SQL的特点,特别是那些没有被SQL标准所涵盖或与InterSystems IRIS 数据平台的统一数据架构有关的特点。假定你已有SQL的知识,本文不是SQL概念或语法的介绍。 表 在InterSystems SQL中,数据是在表内呈现的。每个表都被定义为包含若干列。一个表可以包含零个或多个数据值的行。以下术语大致上是等同的。 数据 关系型数据库术语 InterSystems SQL术语 InterSystems IRIS术语 database schema schema package database table table persistent class field column column property record row row schema SQL schema提供了一种将相关表、视图、存储过程和缓存查询分组的方法。模式的使用有助于防止在表一级的命名冲突,因为一个表、视图或存储过程的名称必须只在其schema内是唯一的。一个应用程序可以在多个schema中指定表。 SQL schema对应于IRIS中持久化的类包。通常情况下,一个模式的名称与它对应的包的名称相同,但是这些名称可能会因为不同的模式命名惯例而不同,或者因为不同的名称被故意指定。 命名:schema.name。如果没有指定schema:例如只有name。InterSystems IRIS会按以下方式提供模式。 对于DDL操作,InterSystems IRIS使用全系统默认的schema名称SQLUser。这个默认是可配置的。它适用于所有命名空间。 对于DML操作,InterSystems IRIS可以使用用户提供的schema搜索路径或全系统默认的schema名称。在动态SQL、嵌入式SQL和SQL Shell中,使用不同的技术来提供schema搜索路径。 在管理门户中查看一个命名空间内的所有现有schema: 从管理门户中选择系统资源管理器,然后选择SQL。用页面顶部的切换选项选择一个命名空间;这将显示可用的命名空间的列表。选择一个命名空间。选择屏幕左边的模式下拉列表。这将显示当前命名空间中的schema列表。从这个列表中选择一个schema; SQL 查询 查询有两种类型:检索数据的查询(SELECT语句)和修改数据的查询(INSERT、UPDATE和DELETE语句)。 你可以以多种方式使用SQL查询: 在ObjectScript中使用嵌入式SQL。 在ObjectScript中使用动态SQL。 调用使用CREATE PROCEDURE或CREATE QUERY创建的存储过程。 使用一个类查询。 使用来自其他环境的ODBC或JDBC接口。 SELECT查询在本指南的查询数据库一章中有描述。 查询是InterSystems IRIS对象或ObjectScript程序的一部分。 Privileges 特权 InterSystems SQL提供了一种方法,通过权限来限制对表、视图等的访问。你可以定义一组用户和角色,并授予他们各种权限(读、写等等)。 数据显示 SelectMode InterSystems SQL使用SelectMode选项来指定数据的显示或存储方式。可用的选项有逻辑模式、显示模式和ODBC模式。 数据在内部以逻辑模式存储,并可以以任何模式显示。每个数据类型类都可以通过使用LogicalToDisplay(), LogicalToODBC(), DisplayToLogical(), ODBCTtoLogical()方法来定义内部逻辑格式和显示格式或ODBC格式之间的转换。 当SQL SelectMode是显示模式时,LogicalToDisplay转换被应用,返回的值被格式化以用于显示。默认的SQL选择模式是逻辑模式;因此默认返回的值是以其存储格式显示的。 模式会影响查询结果集数据的显示格式,也会影响数据值的提供格式,如果提供的数据值与SelectMode不匹配,可能会导致错误或错误的结果。 例如,例如在WHERE子句中,如果DOB是一个以$HOROLOG逻辑格式存储的日期,而WHERE子句指定WHERE DOB > 2000-01-01(ODBC模式),SelectMode = ODBC返回预期的结果。但是,如果SelectMode = 显示模式,则生成SQLCODE -146 无法将日期输入转换为有效的逻辑日期值。如果SelectMode = 逻辑模式,则试图将2000-01-01解析为一个逻辑日期值,并返回0行。 对于大多数数据类型,三种SelectMode模式返回相同的结果。以下数据类型受到SelectMode选项的影响。 日期、时间和时间戳数据类型。 %List数据类型 - 在ODBC选择模式下,列表项之间用逗号分隔符显示。在显示选择模式下,列表项之间以空白分隔符显示。 指定VALUELIST和DISPLAYLIST的数据类型。对于必填字段,如果您在显示模式下,在字段有DISPLAYLIST的表中插入一个值,您输入的显示值必须与DISPLAYLIST中的一个项目完全匹配。对于非必填字段,不匹配的值被转换为NULL值。 空字符串,和空BLOB(流字段)。在逻辑模式下,空字符串和BLOBs由非显示字符$CHAR(0)表示。在显示模式下,它们由一个空字符串("")表示。 SQL的SelectMode可以按以下方式指定。 对于当前进程,使用SetOption("SelectMode")方法。 对于InterSystems SQL Shell会话,使用SET SELECTMODE命令。 对于来自管理门户 "执行查询 "用户界面(系统浏览器,SQL)的查询结果集,使用 "显示模式 "下拉列表。 对于一个动态SQL %SQL.Statement实例,使用%SelectMode属性。 对于嵌入式SQL,使用ObjectScript的 #SQLCompile Select 预处理器指令设置。这个指令允许第四个值,Runtime,它将选择模式设置为RuntimeMode属性的任何设置。RuntimeMode默认为逻辑模式。 #SQLCOMPILE SELECT=Logical #SQLCOMPILE SELECT=Display #SQLCOMPILE SELECT=ODBC 对于的SQL命令CREATE QUERY、CREATE METHOD、CREATE PROCEDURE和CREATE FUNCTION, 使用SELECTMODE关键字。 对于SQL查询中的单个列,使用%EXTERNAL、%INTERNAL和%ODBCOUT函数。 SELECT TOP 5 DOB,%EXTERNAL(DOB) AS ExtDOB Data Collation data collation规定了数值的排序和比较方式,它是InterSystems SQL和InterSystems IRIS对象的一部分。 你可以指定collation类型作为字段/属性定义的一部分。除非另有规定,否则字符串字段/属性默认为命名空间的默认排序。默认情况下,字符串的命名空间默认排序是SQLUPPER。SQLUPPER排序法将字符串转换为大写字母,以便进行排序和比较。因此,除非另有规定,否则字符串的排序和比较是不分大小写的。 你可以指定一个collation类型作为索引定义的一部分,或者使用被索引字段的collation类型。 一个SQL查询可以通过对字段名应用一个collation函数来覆盖已定义的collation类型的字段/属性。ORDER BY子句指定了一个查询的结果集顺序;如果一个指定的字符串字段被定义为SQLUPPER,查询结果顺序是不区分大小写的。 SQL 执行 编写和执行SQL代码的方法包括: 嵌入式SQL:在ObjectScript代码中嵌入SQL代码。 动态SQL:从ObjectScript中执行SQL代码,使用%SQL.Statement类。 Execute()方法:使用%SYSTEM.SQL类的Execute()方法执行SQL代码。 包含SQL代码的存储过程:使用CREATE PROCEDURE或CREATE QUERY创建。 SQL Shell:从终端界面执行的SQL语句。 从管理门户执行的SQL语句:系统资源管理器 -> SQL。 使用InterSystems IRIS对象(类和方法): 定义一个持久的类(一个SQL表)。 定义一个索引。 定义和使用一个类查询。
文章
Jingwei Wang · 七月 14, 2022

InterSystems SQL 的使用 - 第三部分 - 表

创建表 可以通过以下方式定义表: 通过DDL定义表 使用任意数据库管理工具执行DDL(使用ODBC,JDBC连接) MyApp.Person表可以使用DDL CREATE TABLE语句来定义,指定SQL schema.table名称。成功执行这个SQL语句会生成一个相应的持久化类,包名MyApp,类名Person。当使用DDL命令定义一个表时,你不需要指定USEEXTENTSET或创建一个位图范围索引。InterSystems SQL会自动应用这些设置,并将它们包含在预测的持久化类中。默认情况下,CREATE TABLE在相应的类定义中指定了Final类的关键字,表示它不能有子类。 CREATE TABLE MyApp.Person ( Name VARCHAR(50) NOT NULL, SSN VARCHAR(15) DEFAULT 'Unknown', DateOfBirth DATE, Sex VARCHAR(1) ) 使用Objectscript执行DDL 在ObjectScript中使用 Embedded SQL. ClassMethod CreateTable() As %String { &sql(CREATE TABLE Sample.Employee ( EMPNUM INT NOT NULL, NAMELAST CHAR (30) NOT NULL, NAMEFIRST CHAR (30) NOT NULL, STARTDATE TIMESTAMP, SALARY MONEY, ACCRUEDVACATION INT, ACCRUEDSICKLEAVE INT, CONSTRAINT EMPLOYEEPK PRIMARY KEY (EMPNUM))) IF SQLCODE=0{ WRITE "Table created" RETURN "Success"} ELSEIF SQLCODE=-201 { WRITE "Table already exists" RETURN SQLCODE} ELSE { WRITE "Serious SQL Error, returing SQLCODE " RETURN SQLCODE_" "_%msg} } 这个方法试图创建一个Sample.Employee表(以及相应的Sample.Employee类)。如果成功,SQLCODE变量被设置为0;如果不成功,SQLCODE包含一个SQL错误代码,表明失败的原因。 像这样的DDL命令,最常见的失败原因是: SQLCODE -99(特权侵犯)。这个错误表明你没有权限执行所需的DDL命令。一般来说,这是因为应用程序没有确定谁是当前用户。你可以使用$SYSTEM.Security.Login()方法以编程方式完成这个任务。 DO $SYSTEM.Security.Login(username,password) 使用 Dynamic SQL. Class Sample.NewT { ClassMethod DefTable(user As %String, pws As %String) [Language = objectscript] { Do ##class(%SYSTEM.Security).Login(user,pws) SET myddl = 2 SET myddl(1)="CREATE TABLE Sample.MyTest " SET myddl(2)="(NAME VARCHAR(30) NOT NULL,SSN VARCHAR(15) NOT NULL)" SET tStatement = ##class(%SQL.Statement).%New() SET qStatus = tStatement.%Prepare(.myddl) IF qStatus '= 1 { WRITE "%Prepare failed:" DO $System.Status.DisplayError(qStatus) QUIT } SET rset = tStatement.%Execute() IF rset.%SQLCODE =0 {WRITE "Created a table"} ELSEIF rset.%SQLCODE =-201 {WRITE "table already exists"} ELSE {WRITE "Unexpected error SQLCODE=",rset.%SQLCODE} } } 批量执行DDL脚本文件 使用$SYSTEM.SQL.Schema.Run()方法从终端会话中交互式地导入InterSystems SQL DDL脚本文件 使用$SYSTEM.SQL.Schema.ImportDDL("IRIS")方法作为后台作业。这个方法可以导入和执行多个SQL命令,使你能够使用一个txt脚本文件来定义表和视图,并为它们填充数据。 针对特定供应商的%SYSTEM.SQL.Schema Load方法。特定供应商的SQL被转换为InterSystems的SQL并执行。错误和不支持的功能被记录在日志文件中。例如下面的Oracle示例。 SET $namespace = "MYNAMESPACE" DO $SYSTEM.SQL.Schema.LoadOracle() 通过持久化类定义表 当编译时,这个持久化类会自动投射到一个与类定义相对应的关系表中:每个类代表一个表;每个属性代表一个列,以此类推。这个定义在MyApp schema中创建了MyApp.Person持久化类和相应的SQL表Person。持久类的名称Person被用作SQL表的名称。要提供一个不同的SQL表名,你可以使用SqlTableName类的关键字。 Class MyApp.Person Extends %Persistent { Parameter USEEXTENTSET = 1; //USEEXTENTSET 类参数被定义并设置为1,这个参数将表的存储组织成一个更有效的globals集合。 Property Name As %String(MAXLEN=50) [Required]; Property SSN As %String(MAXLEN=15) [InitialExpression = "Unknown"]; Property DateOfBirth As %Date; Property Sex As %String(MAXLEN=1); Index BitmapExtent [Extent, Type = bitmap ] //位图范围索引为范围集中的所有ID创建一个索引。这种设置使得计数和其他操作更加有效。 } 使用持久化类定义在编译时可以创建的相应的表,但是这个表定义不能使用SQL DDL命令进行修改或删除(或者使用管理门户的Drop操作),这些命令会给你提示"'schema.name'类不启用DDL...")。你必须在表类定义中指定[DdlAllowed]以允许这些操作。 Class MyApp.Person Extends %Persistent [DdlAllowed] 根据现有的表(或表或视图)来定义和填充一个新的表。 你指定一个查询和一个新的表名。现有的表名和/或新的表名可以是限定的或非限定的。查询可以包含JOIN语法。查询可以提供列名别名,成为新表中的列名。 可以使用: CREATE TABLE AS SELECT命令 CREATE TABLE Sample.YoungPeople AS SELECT Name,Age FROM Sample.People WHERE Age < 21 $SYSTEM.SQL.Schema.QueryToTable()方法执行。 DO $SYSTEM.SQL.Schema.QueryToTable("SELECT Name,Age,AVG(Age) AS AvgInit FROM Sample.Person WHERE Age < 21","Sample.Youth",1,.errors) QueryToTable()复制了现有表的DDL定义,并将其指定为新表的名称。它复制查询中指定的字段的定义,包括数据类型、最大长度和最小值/最大值,但不复制字段的数据约束,如默认值、要求值或唯一值。它不会从一个字段复制引用到另一个表中。 如果查询指定SELECT *或SELECT %ID,原始表的RowID字段将被复制为数据类型为整数的非必填、非唯一的数据字段。QueryToTable()为新表生成了一个唯一的RowID字段。如果复制的RowID被命名为ID,生成的RowID被命名为ID1。 QueryToTable()为这个新表创建一个相应的持久化类。该持久化类被定义为DdlAllowed。新表的所有者是当前用户。 新表被定义为默认存储=YES和支持位图索引=YES,不管源表中的这些设置如何。为新表创建的唯一索引是IDKEY索引,没有生成位图范围索引。被复制的字段的索引定义不会被复制到新表中。 $SYSTEM.SQL.Schema.TableExists()方法可以用来确定一个表的名字是否已经存在。 RowID 在SQL中,每条记录都由一个唯一的整数值来标识,称为RowID。 在InterSystems SQL中,你不需要指定一个RowID字段。当你创建一个表并指定所需的数据字段时,会自动创建一个RowID字段。这个RowID在内部使用,但没有被映射到一个类属性。默认情况下,只有当一个持久化类被投射到一个SQL表时,它的存在才是可见的。在这个投射表中,会出现一个额外的RowID字段。 默认情况下,这个字段被命名为 "ID "并被分配到第1列,且这个字段是自增的,不会被重复使用。因此,如果记录被插入和删除,RowID值将是升序的数字序列,但可能不是数字连续的。且ALTER TABLE不能修改或删除RowID字段的定义。RowID计数器可以通过TRUNCATE TABLE命令被重置,但它不会被DELETE命令重置,即使DELETE命令删除了表中的所有记录。如果没有数据被插入到表中,或者TRUNCATE TABLE被用来删除所有表的数据,IdLocation存储关键字的global是未定义的。 默认情况下,InterSystems IRIS将这个字段命名为 "ID",然而这个字段名并不保留。RowID字段名在每次编译表的时候都会重新建立。如果用户定义了一个名为 "ID "的字段,当表被编译时,InterSystems IRIS将RowID命名为 "ID1"。例如,如果用户随后使用ALTER TABLE来定义一个名为 "ID1 "的字段,表的编译就会将RowID重命名为 "ID2",以此类推。在一个持久化的类定义中,你可以使用SqlRowIdName类关键字来直接指定这个类所投射的表的RowID字段名。由于这些原因,应该避免用名字来引用RowID字段。 InterSystems SQL提供了%ID伪列名(别名),它总是返回RowID值,不管分配给RowID的字段名是什么。(InterSystems TSQL提供了$IDENTITY伪列名,它也做同样的事情)。 默认情况下,使用CREATE TABLE定义的表使用$SEQUENCE执行ID分配,允许多个进程同时快速填充表。当$SEQUENCE被用来填充表时,一个RowID值的序列被分配给一个进程,然后按顺序分配它们。因为并发的进程使用他们自己分配的序列来分配RowID,所以不能假设由一个以上的进程插入的记录是按照插入的顺序进行的。 当使用CREATE TABLE创建一个表时,RowID默认是隐藏的。一个隐藏的字段不会被SELECT *显示,并且是PRIVATE。当你创建一个表的时候,你可以指定%PUBLICROWID关键字来使RowID不被隐藏并且是公开的。这个可选的%PUBLICROWID关键字可以在CREATE TABLE逗号分隔的表元素列表中的任何地方指定,但不能在ALTER TABLE中指定。 当创建一个投射为表的持久化类时,RowID默认不会被隐藏。它通过SELECT *显示,并且是公共的。你可以通过指定类的关键字SqlRowIdPrivate来定义一个RowID为隐藏和PRIVATE的持久化类。 作为外键引用的RowID必须是公共的。默认情况下,一个具有公共RowID的表不能被用作源表或目标表,例如使用 INSERT INTO Sample.DupTable SELECT * FROM Sample.SrcTable 将数据复制到一个重复的表。 你可以使用管理门户SQL界面来查看RowID是否被隐藏。 基于其他字段的RowID 通过定义一个投射表的持久化类,你可以将RowID定义为来自一个字段或一个字段组合的值。要做到这一点,用IdKey索引关键字指定一个索引。例如,通过PatientName字段的值指定索引定义 IdxId On PatientName [IdKey]; 或者通过PatientName和SSN字段的合并值指定索引定义 IdxId On (PatientName,SSN) [IdKey] 但是,基于字段的RowID比采取系统分配的连续正整数的RowId效率低。 在INSERT中:为构成RowId的字段或字段组合指定的值必须是唯一的。指定一个非唯一的值会产生一个SQLCODE -119 "UNIQUE或PRIMARY KEY约束在INSERT时唯一性检查失败"。 在UPDATE中:默认情况下,组成RowId的每个字段的值是不可修改的。试图修改这些字段之一的值会产生一个SQLCODE -107 "不能UPDATE RowID或基于字段的RowID"。 当一个RowID基于多个字段时,RowID的值是由||操作符连接的每个组成字段的值。例如,Ross,Betsy||123-45-6789。InterSystems IRIS试图确定基于多个字段的RowID的最大长度;如果它不能确定最大长度,RowID长度默认为512。 主键 InterSystems IRIS提供两种方法来唯一地识别表中的行:RowID和主键。 可选的主键是一个有意义的值,应用程序可以用它来唯一地识别表中的一行(例如在连接中)。一个主键可以是用户指定的数据字段,也可以是一个以上的数据字段的组合。主键值必须是唯一的,但不要求是整数值。RowID是一个内部使用的整数值,用于识别表中的一行。通常情况下,主键是一个由应用程序生成的值,而RowID是一个由InterSystems IRIS生成的唯一整数值。 系统会自动创建一个master map来访问使用RowID字段的数据行。如果你定义了一个主键字段,系统会自动创建并维护一个主键索引。 显然,有两个不同的字段和索引来识别行,这种双重性不一定是好事。你可以通过以下两种方式中的任何一种解决单一的行标识符和索引: 使用应用程序生成的主键值作为IDKEY。你可以通过在类定义中使用关键字PrimaryKey和IdKey来识别主键索引,当然,也可以从DDL中这样做。这使得主键索引成为表的主映射。因此,主键将被用作行的主要内部地址。如果主键由一个以上的字段组成,或者主键值不是整数,这可能会降低效率。 不要使用应用程序生成的主键值,而是使用应用程序内系统生成的RowID整数作为应用程序使用的主键(例如在连接中)。这样做的好处是,整数的RowID适合于更有效的处理,包括使用位图索引。 根据应用程序的性质,你可能希望解决一个单一的行标识符和索引,或者为应用程序生成的主键和系统生成的RowID设置单独的索引。 特殊字段:RowVersion字段 , 自增字段, 和 Serial 计数器字段 InterSystems SQL支持三种特殊用途的数据类型,用于自动递增计数器的值。这三种数据类型都是扩展%Library.BigInt数据类型类的子类。 %Library.RowVersion: 计算对所有RowVersion表的插入和更新的命名空间。只有包含ROWVERSION字段的表的插入和更新才会增加这个计数器。ROWVERSION值是唯一的,不可修改的。这个全命名空间的计数器从不重置。可以通过指定一个数据类型为ROWVERSION(%Library.RowVersion)的字段来创建一个RowVersion字段。你只能在每个表中指定一个ROWVERSION数据类型字段。试图创建一个有一个以上ROWVERSION字段的表会导致5320编译错误。RowVersion字段不应该被包含在唯一键或主键中。RowVersion字段不能成为IDKey索引的一部分。 %Library.Counter(也被称为SERIAL计数器字段)。计算插入到表中的次数。默认情况下,这个字段接收一个自动递增的整数。然而,用户可以为这个字段指定一个非零的整数值。用户可以指定一个重复的值。如果用户提供的值大于系统提供的最高值,自动递增计数器被设置为从用户指定的值开始递增。这个计数器通过TRUNCATE TABLE命令被重置为1。它不会被DELETE命令重置,即使DELETE命令删除了表中的所有记录。分片的表不能有SERIAL计数器字段。 %Library.AutoIncrement: 计算插入到表中的次数。默认情况下,这个字段接收一个自动递增的整数。然而,用户可以为这个字段指定一个非零的整数值。用户可以指定一个重复的值。指定一个用户值对自动递增计数器没有影响。 所有这三个字段和IDENTITY字段都返回AUTO_INCREMENT = YES,如下面的例子所示。 查看表定义 表信息 INFORMATION.SCHEMA.TABLES持久化类显示当前命名空间中所有表(和视图)的信息。包括模式和表名,表的所有者,以及是否可以插入新记录。TABLETYPE属性表明它是一个基础表还是一个视图。 SELECT Table_Type,Table_Schema,Table_Name,Owner FROM INFORMATION_SCHEMA.TABLES INFORMATION.SCHEMA.CONSTRAINTTABLEUSAGE持久化类为当前命名空间中的每个表定义的每个主键(显性或隐性)、外键或唯一约束。 INFORMATION.SCHEMA.KEYCOLUMNUSAGE为当前命名空间中的每个表的每个已定义的约束。 也可以使用管理门户SQL界面中的目录详情来查看表信息。 列信息 GetColumn 方法 SET stat = ##class(%SYSTEM.SQL.Schema).GetAllColumns("MyApp.Person",.byname,.bynum) IF stat=1 { SET i=1 WHILE $DATA(bynum(i)) { WRITE "name is ",bynum(i), "column is ", i, ! } }ELSE{ WRITE "GetAllColumns() cannot locate specified table"} 生成结果: name is ID col num is 1 name is Age col num is 2 name is Home col num is 3 name is Name col num is 4 SQL脚本 INFORMATION_SCHEMA.COLUMNS可以列出指定schema的所有列名: SELECT TABLE_NAME,COLUMN_NAME,ORDINAL_POSITION,DATA_TYPE,CHARACTER_MAXIMUM_LENGTH,COLUMN_DEFAULT,IS_NULLABLE,UNIQUE_COLUMN,PRIMARY_KEY FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='MyApp' ​ 或者 ​ SELECT TOP 0 * FROM tablename. Constraints信息 INFORMATION.SCHEMA.TABLECONSTRAINTS持久化类列出了表名,约束类型和约束名称。约束类型包括UNIQUE, PRIMARY KEY, 和 FOREIGN KEY。 SELECT Table_Schema,Table_Name,Constraint_Type,Constraint_Name FROMINFORMATION_SCHEMA.TABLE_CONSTRAINTS INFORMATION.SCHEMA.CONSTRAINTCOLUMNUSAGE持久化类列出了表名、列名和约束名称。如果一个约束涉及到多个列,那么每一个列都会列出一个单独的项目。 SELECT Table_Schema,Table_Name,Column_Name,Constraint_Name FROMINFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE INFORMATION.SCHEMA. REFERENTIALCONSTRAINTS持久化类列出了外键约束,包括引用表(CONSTRAINT_SCHEMA, CONSTRAINT_TABLE_NAME),被引用表(UNIQUE_CONSTRAINT_SCHEMA, UNIQUE_CONSTRAINT_TABLE),外键名称(CONSTRAINT_NAME),以及UPDATE和DELETE参考动作(UPDATE_RULE,DELETE_RULE),值为NO ACTION,SET DEFAULT,SET NULL,或CASCADE。 SELECT Constraint_Table_Name,Unique_Constraint_Table,Constraint_Name,Update_Rule,Delete_Rule FROMINFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS 连接外部表 在InterSystems SQL中,你也可以有 "外部表",即在SQL字典中定义的表,但存储在一个外部关系数据库中。外部表的作用就像它们是本地的InterSystems IRIS表一样:你可以对它们发出查询,执行INSERT、UPDATE和DELETE操作。 对外部数据库的访问是由InterSystems SQL Gateway提供的,它使用ODBC或JDBC提供透明的连接。
文章
Michael Lei · 十二月 13, 2022

InterSystems IRIS 嵌入式 Python 模板

嵌入式 Python 模板 今天你们分享一个简单的[嵌入式 Python 模板](https://openexchange.intersystems.com/package/iris-embedded-python-template),我建议将其作为任何使用 InterSystems IRIS 并将使用嵌入式 Python 的通用项目的起点。 功能: * 随时可用的嵌入式 Python; * 3 种嵌入式 Python 开发方式示例; * 随时可用的 VSCode 开发; * 支持 Docker; * 支持在线演示; * 随时可用的 ZPM 优先开发。 下面讨论一下这些功能! 我们先来谈谈嵌入式 Python。 此功能在 InterSystems IRIS 2021.2 中提供,它允许使用 InterSystems IRIS 通过 Python 开发解决方案。 IRIS 2021.2 及以上版本允许使用 InterSystems IRIS 在共享内存环境中执行 Python 脚本,这为 Python 开发者在使用代码与数据相近的数据库时提供了独特的选项。  ### 3 种使用嵌入式 Python 进行开发的模式 ### **从 ObjectScript 调用 Python 库** 此操作因 [%SYS.Python](https://docs.intersystems.com/irislatest/csp/documatic/%25CSP.Documatic.cls?&LIBRARY=%25SYS&CLASSNAME=%25SYS.Python) 类而变为可能,该类允许导入 Python 库并通过 ObjectScirpt 调用 Python。 [文档](https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI.Page.cls?KEY=AEPYTHON#AEPYTHON_callpython_library)、[示例](https://github.com/intersystems-community/iris-embedded-python-template/blob/be578226b7a0c583df1f7b693b1bdae074efb1bd/src/dc/python/PersistentClass.cls#L17)。 请查看以下代码: <span class="hljs-keyword">ClassMethod</span> Today() <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Status</span> { <span class="hljs-keyword">Set</span> sc = <span class="hljs-built_in">$$$OK</span> <span class="hljs-keyword">Set</span> dt = <span class="hljs-keyword">##class</span>(<span class="hljs-built_in">%SYS.Python</span>).Import(<span class="hljs-string">"datetime"</span>) <span class="hljs-keyword">write</span> dt.date.today().isoformat() <span class="hljs-keyword">Return</span> sc } ### 使用 Python 编写 ObjectScript 类方法 事实上,现在开发者可以使用纯 Python 在方法签名和代码中添加 [Language=python] 标签。 还有一个辅助 Python 库“iris”,可以用于引用 ObjectScript 类和全局变量。 [文档](https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI.Page.cls?KEY=AEPYTHON#AEPYTHON_runpython_method)、[示例](https://github.com/intersystems-community/iris-embedded-python-template/blob/224be7f5bf80ea0f588f555c7f9e8c8d10c90c10/src/dc/python/PersistentClass.cls#L17)、示例代码: ClassMethod CreateRecordPython(propValue As %VarString, ByRef id As %Integer) [ Language = python ] { <span class="hljs-keyword">import</span> iris obj=iris.cls(__name__)._New() obj.Test=propValue sc=obj._Save() id=obj._Id() <span class="hljs-keyword">return</span> sc } ### 使用纯 Python 编写 InterSystems IRIS 解决方案代码 这是开发者可以选择的第三种处理 IRIS 的方式。  这里,Python 脚本需要连接到 IRIS,此操作可以通过环境变量和设为“On”的 CallIn 服务来完成,请参见下面的详细信息。 设置完后,使用 IRIS 在共享内存中执行 Python 脚本。 在这里,“iris”库也非常有用。 [文档](https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI.Page.cls?KEY=AEPYTHON#AEPYTHON_runpython_script)、[示例](https://github.com/intersystems-community/iris-embedded-python-template/blob/master/python/irisapp.py)。  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_rec</span><span class="hljs-params">(var)</span>:</span> obj=iris.cls(<span class="hljs-string">'dc.python.PersistentClass'</span>)._New() obj.Test=var obj._Save() id=obj._Id() <span class="hljs-keyword">return</span> id <span class="hljs-comment"># test record creation</span> <span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime now=str(datetime.now()) print(<span class="hljs-string">"Creating new record in dc.python.PersistentClass"</span>) print(create_rec(now)) <span class="hljs-comment">## run SQL and print data</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run_sql</span><span class="hljs-params">(query)</span>:</span> rs=iris.sql.exec(query) <span class="hljs-keyword">for</span> idx, row <span class="hljs-keyword">in</span> enumerate(rs): print(<span class="hljs-string">f"[<span class="hljs-subst">{idx}</span>]: <span class="hljs-subst">{row}</span>"</span>) query=<span class="hljs-string">"Select * from dc_python.PersistentClass"</span> print(<span class="hljs-string">"Running SQL query "</span>+query) run_sql(query) ### 支持 Docker 模板仓库在容器中运行 IRIS,并设置嵌入式 Python 调整所需的所有内容。  环境变量。 嵌入式 Python 需要设置特定的环境变量来连接到 IRIS 并运行 Python 脚本。 下面是 [dockerfile](https://github.com/intersystems-community/iris-embedded-python-template/blob/be578226b7a0c583df1f7b693b1bdae074efb1bd/Dockerfile#L13-L17) 中有帮助的设置: # init Python env ENV PYTHON_PATH=/usr/irissys/bin/irispython ENV SRC_PATH=/irisrun/repo ENV IRISUSERNAME "SuperUser" ENV IRISPASSWORD "SYS" ENV IRISNAMESPACE "USER" 此外,嵌入式 Python 需要将 CallIn 服务设为“on”,此操作在构建 docker 的阶段在 [iris.script](https://github.com/intersystems-community/iris-embedded-python-template/blob/224be7f5bf80ea0f588f555c7f9e8c8d10c90c10/iris.script#L7) 中完成: <span class="hljs-comment">; enabling callin for Embedded Python</span> <span class="hljs-keyword">do</span> <span class="hljs-keyword">##class</span>(Security.Services).Get(<span class="hljs-string">"%Service_CallIn"</span>,.prop) <span class="hljs-keyword">set</span> prop(<span class="hljs-string">"Enabled"</span>)=<span class="hljs-number">1</span> <span class="hljs-keyword">set</span> prop(<span class="hljs-string">"AutheEnabled"</span>)=<span class="hljs-number">48</span> <span class="hljs-keyword">do</span> <span class="hljs-keyword">##class</span>(Security.Services).Modify(<span class="hljs-string">"%Service_CallIn"</span>,.prop) 另外,您的解决方案可能需要安装一些 Python 库。 这通过仓库根目录中的 [requirements.txt](https://github.com/intersystems-community/iris-embedded-python-template/blob/master/requirements.txt) 和 [dockerfile](https://github.com/intersystems-community/iris-embedded-python-template/blob/224be7f5bf80ea0f588f555c7f9e8c8d10c90c10/Dockerfile#L22) 中的 pip3 调用来实现: pip3 install -r requirements.txt && \ ### 随时可用的 VSCode 开发 使用 docker 在 VSCode 中开发非常方便。 如果想要在 docker IRIS 解决方案中使用嵌入式 Python 进行开发,VSCode 需要切换到 [Devcontainer 模式](https://code.visualstudio.com/docs/remote/containers)。 为此,将 [devcontainer.json 文件](https://github.com/intersystems-community/iris-embedded-python-template/blob/master/.devcontainer/devcontainer.json)添加到 .devcontainer 文件夹中。 该文件描述了需要使用的 docker 服务(本例中为 iris),这可以帮助在 VSCode 中运行 Python 脚本,这些脚本将由在容器中运行的 IRIS 使用的 Python 引擎提供服务。 devcontainer.json 文件还有一个部分,其中说明了需要在容器模式下使用哪些[扩展](https://github.com/intersystems-community/iris-embedded-python-template/blob/224be7f5bf80ea0f588f555c7f9e8c8d10c90c10/.devcontainer/devcontainer.json#L43): "extensions": [ "ms-python.python", "ms-python.vscode-pylance", "intersystems-community.vscode-objectscript", "intersystems.language-server", "intersystems-community.servermanager", "ms-vscode.docker" ], ### 通过 ZPM 安装嵌入式 Python 解决方案 此模板被设置为“ZPM 优先”开发仓库。 这意味着所有开发代码都已在 module.xml 中介绍,并且每次构建 docker 镜像时都作为 ZPM 模块安装,开发者每次编码时都在 iris.script 中使用[以下行](https://github.com/intersystems-community/iris-embedded-python-template/blob/224be7f5bf80ea0f588f555c7f9e8c8d10c90c10/iris.script#L13)开头: zpm "load /home/irisowner/irisbuild/ -v":1:1 ZPM 模块中还介绍了嵌入式 Python 代码,它通过 [FILECOPY](https://github.com/intersystems-community/iris-embedded-python-template/blob/224be7f5bf80ea0f588f555c7f9e8c8d10c90c10/module.xml#L11) 进行安装: <FileCopy Name="python/" Target="${libdir}python/"/> 此表达式表示,我们想要将所有 Python 脚本打包在仓库中的 /python 文件夹下,并将其安装在目标 IRIS 安装程序的 libdir 的 python/ 文件夹中。 如果将 Python 脚本复制到 ${libdir}python/ 文件夹下,则可以在目标 IRIS 机器中通过 ObjectScirpt 或 Python 对其进行导入调用。 _**注意: 确保您的文件夹名称唯一,以免意外替换其他 Python 代码。**_ 希望该模板对您有用。 欢迎提供反馈,尤其是拉取请求!
文章
Jingwei Wang · 七月 21, 2022

InterSystems SQL 的使用 - 第四部分 - 视图

视图为存储查询,提供了物理表的所有灵活性和安全权限。所有的视图都是可更新的或只读的。 注意:不能对只读的数据库中的数据创建视图。不能对存储在通过ODBC或JDBC网关连接的Informix表中的数据创建视图。这是因为InterSystems IRIS查询转换在FROM子句中使用子查询,而Informix不支持FROM子句的子查询。 创建视图 视图名称可以是合格的的或不合格的。一个没有限定的视图名称是一个简单的标识符。MyView。一个合格的视图名称由两个简单的标识符组成,一个schema名称和一个视图名称,用句号隔开, 例如MySchema.MyView。视图名和表名遵循相同的命名规则,并对未限定的名称执行相同的schema名称解析。同一模式中的视图和表不能有相同的名称。 你可以通过几种方式定义视图: 使用SQL CREATE VIEW命令(在DDL脚本中或通过JDBC或ODBC)。 CREATE VIEW MySchema.MyView (ViewCol1, ViewCol2, ViewCol3) AS SELECT TableCol1, TableCol2, TableCol3 FROM MyTable 使用管理门户的创建视图界面。 系统操作 -> SQL -> 操作 -> 创建视图 这将显示 "创建视图 "窗口,如图所示: schema:您可以决定将视图包含在现有schema中,或者创建一个新的schema。 视图名称:一个有效的视图名称。在同一模式中,你不能对表和视图使用相同的名称。 带检查选项:选项有READONLY、LOCAL、CASCADED。 授予视图的所有权限给_PUBLIC:如果选择了这个选项,这个选项会给所有用户执行这个视图的权限。默认是不给所有用户访问该视图的权限。 查看文本:你可以通过以下三种方式中的任何一种指定视图文本。 在 "查看文本 "区域键入一个SELECT语句。 使用查询生成器创建一个SELECT语句,然后按确定将此查询提供给视图文本区。 如果你在管理门户SQL界面左侧选择一个缓存查询名称(例如%sqlcq.USER.cls4),然后调用创建视图,这个缓存查询就会提供给视图文本区。注意,在视图文本区,你必须在保存视图文本之前用实际值替换变量引用(问号)。 使用Objectscript执行DDL ClassMethod CreateTable() As %String { &sql(CREATE VIEW Sample.VSrStaff AS SELECT Name AS Vname,Age AS Vage FROM Sample.Person WHERE Age>75) IF SQLCODE=0{ WRITE "Created a view"} ELSEIF SQLCODE=-201 { WRITE "View already exists" RETURN SQLCODE} ELSE { WRITE "Serious SQL Error, returing SQLCODE " RETURN SQLCODE_" "_%msg} } $SYSTEM.SQL.Schema.ViewExists()方法可以用来确定一个视图名称是否已经存在。 查看视图定义 视图信息 SELECT * FROM INFORMATION_SCHEMA.VIEWS 视图的依赖表 NFORMATION.SCHEMA.VIEWTABLEUSAGE持久化类显示当前命名空间中的所有视图和它们所依赖的表。 通过SQL脚本显示视图依赖表 SELECT View_Schema,View_Name, Table_Schema,Table_Name FROM INFORMATION_SCHEMA.VIEW_TABLE_USAGE 通过ObjectScript显示依赖表 SET statemt = ##class(%SQL.Statement).%New() SET cqStatus = statemt.%PrepareClassQuery("%Library.SQLCatalog","SQLViewDependsOn") IF cgStatus '= 1 { WRITE "PrepareClassQuery failed:" DO $System.Status.DisplayError(cgStatus) QUIT } SET rset = statemt.%Execute("vschema.vname") DO rset.%Display() 如果调用者没有视图所依赖的表的权限,该表及其模式将被列为NOT PRIVILEGED。这允许没有表权限的调用者确定视图所依赖的表的数量,但不能确定表的名称。 View ID: %VID InterSystems IRIS为视图或FROM子句返回的每条记录分配一个整数的视图ID(%VID)。与表的行ID号一样,这些视图的行ID号也是系统分配的、唯一的、非空的、非零的和不可修改的。这个%VID通常对用户来说是不可见的,只有在明确指定时才会返回。它作为数据类型INTEGER返回。因为%VID值是连续的整数,如果视图返回有序的数据,它们就更有意义;视图只有在与TOP子句配对时才能使用ORDER BY子句。 CREATE VIEW Sample.VSrStaff AS SELECT TOP ALL Name AS Vname,Age AS Vage FROM Sample.Person WHERE Age>75 ORDER BY Name 下面的例子返回VSrStaff视图定义的所有数据(使用SELECT *),并且还指定要返回每一行的视图ID。与表的行ID不同,视图的行ID在使用星号语法时不会显示;只有在SELECT中明确指定时才会显示。 SELECT *,%VID AS ViewID FROM Sample.VSrStaff %VID可以用来进一步限制SELECT从视图返回的行数,如下面的例子所示。 SELECT *,%VID AS ViewID FROM Sample.VSrStaff WHERE %VID BETWEEN 5 AND 10 因此,%VID可以用来代替TOP(或者作为TOP的补充)来限制查询返回的记录的数量。一般来说,TOP子句用于返回数据记录的一个小子集;%VID用于返回大部分或全部数据记录,将记录返回到小子集的中。这个功能可能很有用,特别是对于Oracle查询(%VID很容易映射到Oracle ROWNUM)。然而,用户应该意识到,与TOP相比,使用%VID有一些性能限制。 %VID不执行time-to-first-row的优化。TOP的优化是尽可能快地返回第一行数据。%VID的优化是为了尽可能快地返回完整的数据集。 如果查询指定了排序的结果,%VID不会执行有限的排序(这是由TOP执行的特殊优化)。查询首先对完整的数据集进行排序,然后使用%VID对返回的数据集进行限制。TOP是在排序前应用的,所以SELECT执行的是有限的排序,只涉及一个受限制的行子集。 为了保持对第一行的优化时间和有限的排序优化,你可以使用一个带有TOP和%VID组合的FROM子句子查询。 SELECT *,%VID AS SubQueryID FROM (SELECT TOP 10 Name,Age FROM Sample.Person WHERE Age > 75 ORDER BY Name) WHERE %VID > 4 不能对指定了%VID的查询进行并行执行,即使明确指定了%PARALLEL关键字。
公告
Claire Zheng · 八月 11, 2022

网络研讨会:使用ECP在AWS上扩展 InterSystems FHIR Server

Hi 社区成员们, 我们很高兴地宣告 社区网络研讨会 回归了! 我们诚邀您参加 @Ron.Sweeney1582 主讲的 使用ECP在AWS上扩展InterSystems FHIR Server 网络研讨会。 Join this webinar to make a technical deep dive, see a demonstration, and benchmark horizontal scaling InterSystems FHIR Server on Amazon Web Services with Enterprise Cache Protocol (ECP). 欢迎加入此次网络研讨会,深入了解技术,观看演示,并在AWS上使用企业缓存协议(ECP)基准测试水平扩展InterSystems FHIR Server。 ⏱ 时间: 8月18日(周四)8am (美国东部时间) | 2:00pm (中欧夏季时间)| 8:00pm (北京时间)👨‍🏫 主讲人: @Ron.Sweeney1582, 全栈架构师,来自Integration Required 关于 Integration Required: 我们是一个针对InterSystems®工作负载的全栈技术交付团队,可根据您的安全状况和组织部署标准进行定制。凭借InterSystems®十年的合作伙伴关系和对客户满意度的严格坚持,客户对我们充满信任,我们能够实现最佳实践。 那么,不要错过这次机会!来了解更多关于扩展FHIR、ECP和AWS的知识吧! Don't miss this opportunity to learn more about scaling FHIR, ECP and AWS and how to mix it all! >> 点击注册 <<