当您知道将使用对象关系映射器 (ORM)维基百科访问数据库时,需要注意哪些数据库设计问题?另请参阅实体框架 NHibernate 或 LLBLGenPro。
例如,我将注意 SqlServer 的 RPC 调用的 2100 参数限制。当使用 LLBLgen 并在使用复合主键时连接表时,这是一个问题,请参阅复合键的 MSDN 文章。
在更新一行时,许多 ORM 工具发出一个 UPDATE 语句,设置与该特定实体关联的每一列。
优点是您可以轻松地批量更新语句,因为UPDATE
无论您更改什么实体属性,语句都是相同的。此外,您甚至还可以使用服务器端和客户端语句缓存。
所以,如果我加载一个实体并且只设置一个属性:
Post post = entityManager.find(Post.class, 1L);
post.setScore(12);
Run Code Online (Sandbox Code Playgroud)
所有列都将被更改:
UPDATE post
SET score = 12,
title = 'High-Performance Java Persistence'
WHERE id = 1
Run Code Online (Sandbox Code Playgroud)
现在,假设我们也有一个关于该title
属性的索引,数据库难道不应该意识到该值无论如何都没有改变吗?
在这篇文章中,Markus Winand 说:
所有列的更新显示了我们在前几节中已经观察到的相同模式:响应时间随着索引的增加而增加。
我想知道为什么会有这种开销,因为数据库将关联的数据页从磁盘加载到内存中,因此它可以确定是否需要更改列值。
即使对于索引,它也不会重新平衡任何内容,因为对于未更改的列,索引值不会更改,但它们已包含在 UPDATE 中。
是不是和冗余不变列关联的B+树索引也需要导航,数据库才意识到叶子值还是一样的?
当然,一些 ORM 工具允许您只更新更改的属性:
UPDATE post
SET score = 12,
WHERE id = 1
Run Code Online (Sandbox Code Playgroud)
但是,当不同行的不同属性更改时,这种类型的 UPDATE 可能并不总是从批量更新或语句缓存中受益。
嗯,这是假设的场景,但我想了解的是从死后日志(例如 SQL Server Profiler 跟踪)到识别 ORM 情况下的代码的路径。为了让它不会太模糊,请考虑这样的场景:
那么,在这种情况下,DBA(也是 VB.Net 开发人员)从日志中诊断哪些代码(在这种情况下,Linq 查询)造成问题的通用路径是什么?在这种情况下,该应用程序正常,但会影响使用相同数据库/服务器的其他应用程序的响应时间。
那会与 Java+Hiberate 进程有很大不同吗?
编辑:我想了解从跟踪到罪魁祸首元查询的路径。如果应用程序中有 SQL,这意味着“在文件中查找”会话(在极端情况下可能带有一些正则表达式)可以将检查任务的目标减少到几十个可疑对象,而不是十分之一甚至数百个源文件。使用 ORM,如何使用 ORM(在这种情况下:EF)到达那个阶段?
让我给你一些设置。我们在 MySQL 5.1 上有一个 InnoDB 表,有近 2000 万条记录,没有外键,以及我们所做的查询的适当索引。我们正在为 .NET Entity Framework 使用最新的 6.3.5 MySQL 版本。通常我们习惯于处理 SQL Server 和实体框架,但在这个项目中我们决定尝试一下 MySQL。
我对这个问题有一些理论,但让我先做代码设置
EF LINQ 查询
var failsForAcct1001 = db.Failures.Where(x => x.AccountId == 1001);
/* farther down and later on in the code */
return failsForAcct1001.OrderBy(x => x.FailureId).Take(50);
Run Code Online (Sandbox Code Playgroud)
生成的 MySQL 代码
请忽略列名,它们不是理解问题所必需的
select
External1.FailureId,
External1.col2,
External1.col3,
from (select
Inner1.FailureId,
Inner1.col2,
Inner1.col3,
from Failures Inner1
where External1.AccountId = 1001
) External1
order by External1.FailureId
limit 50
Run Code Online (Sandbox Code Playgroud)
生成的这个 SQL 与 SQL Server 中发生的情况非常相似,SQL 处理它没有问题。这不仅仅是一个实体框架问题,当我接受这个查询并在 MySQL …
这个问题的灵感来自发布到最新 ServerFault 博客文章的评论:
你们还在使用 LINQ to SQL 吗?
我知道我可以使用SQL Server Profiler和/或该ToTraceString
方法来查看生成的查询和分析他们自己。但是,我正在寻找具有管理由使用实体框架的应用程序访问的数据库的实践经验的人的意见。
实体框架查询是性能问题的常见原因吗?
在这种情况下可以优化 LINQ 查询还是原始 Transact-SQL 是唯一的解决方案?
我正在处理一组可以移除孩子的关系,但我显然不想失去孙子和父母之间的联系。我确实考虑过将孩子标记为“已故”(在这篇文章中使用相关术语),但后来我最终会被困在我的数据库中的一堆已故孩子,谁想要这样(只是为了保持关系)?
如果删除父项,则删除其所有后代。此外,它的工作方式类似于“正常”关系,其中孙子和子项始终具有相同的顶级父级。层次结构固定为 3 个级别(如上所示)。最后,Parent、Child 和 Grandchild 都是不同的类型(例如,我们不是在谈论 3 个“人类”,他们没有相同的基础)。
然而,让孙子跟踪父母感觉有点奇怪,因为这种关系通常可以从父子关系中推导出来。虽然,我想不出另一种方法。
这个模型有效吗?或者有不同的方法吗?
支持我们软件产品的数据库具有如下表设计:
Positions
ID Name Parts
1 One 12345
2 Two 12346
3 Three 12347
Collections
ID TableID Collection
12345 1;1 1;2
12346 1;1 3;4
12347 1;2;2 5;1;2
Parts
ID Name
1 TestOne
2 TestTwo
3 TestThree
4 TestFour
5 TestFive
SubParts
1 SubPartOne
2 SubPartOne
Run Code Online (Sandbox Code Playgroud)
从上面的例子来看,每个Position
都有一个 集合Parts
,但是这些都被一般地(没有外键约束)映射到Collections
表中。该Collections
表跟踪所有对象之间的所有关系,而不仅仅是上面显示的示例表之间的关系,并且将在使用集合的任何时候使用。
这意味着如果我想获得Position
ID 为 1 的及其所有部分。我必须做三个查询:
SELECT * FROM Positions WHERE ID = 1
SELECT * FROM Collections WHERE ID = 12345
Split the string …
Run Code Online (Sandbox Code Playgroud) 编辑: 这个问题是关于如何处理在整个系统设计中出现的许多问题,这使得系统的某些部分偏离了通用标准。例如,使用自己的程序代码管理业务模型中的所有内容,甚至关系完整性。这给数据库和持久层带来了一种糟糕设计的味道,将其用作“将某些内容转入并以某种方式再次取出”的地方,而不是结构化存储。我问了这个问题,因为在我看来,NoSQL 文档存储就像一个选项,可以将已经无模式(或非常松散的模式)数据库移动到默认情况下没有模式的数据库。此外,我必须指出,尽管这里描述了一些缺陷,但整个系统根本不是一个坏系统。此外,一些问题,例如版本控制,已经有了解决方案或已经实施。
想想你看到的一个软件系统,基于经典的关系数据库(SQL Server、Oracle)、NHibernate作为对象关系映射器(ORM)、顶部的业务逻辑模型层和大量模块(几百个) ,主要是基于 .NET 的服务和一些 Web 服务(带有客户端,每个系统/客户最多约 100 个,公司网络,非公共)。操作方式主要是OLTP,写/CUD访问是工作负载的重要组成部分。生产数据库通常大约为 10GB,但大小总是远低于 100GB(因此没有“大数据”)。它确实工作得很好,但对我来说,数据库和 ORM 实现有几种反模式(对于关系数据库)的味道。也许这些实现对于另一种数据库会更好——面向文档(“NoSQL”)或内存数据库。
省略了许多关系数据库和支持 ORM 的功能:表被强烈反规范化,外键关系丢失或不可能,例如由于元数据表引用不同的主表,列如IdInTable INT, OwnerTable INT
. NHibernate 几乎没有映射对象关系(并且通常存在不适合它的表结构的问题)。相反,这些是在业务逻辑中实现的(有时会导致孤立的子对象或低效的数据库访问,见下文)。
基础之下的非规范化:增加非 1st NF 数据的使用:带有 XML、逗号分隔列表或复合数值列的 nclob/nvarchar(max) 列(例如,任务类型 123 的 123、10123、40123,但模块配置不同由 0,1,4 * 10000 标识)。前两个包含数据库相关、逻辑“外键”和数据模型相关值,例如<UserType>AdminUser</UserType>
(要检查LIKE '%...%'
)。这主要是由于许多快速发布、短暂存在和自定义的值不应该进入主模式,或者更容易通过 XML 值实现。
非 2nd NF 数据,包括由触发器、后续存储过程或应用程序复制到其他表中的表内容。例如,将表列值复制到“垂直”元数据表,这再次复制到元数据的“水平”或“旋转”表示(每个元数据类型为一列),因为某些应用程序只能使用元数据或水平元数据. 经常要求使用“垃圾箱结构”(将从各种来源收集的数据转储到一个 nclob/nvarchar(max)“垃圾箱”列中,并让应用程序搜索它,而不是许多不同的来源)。
业务逻辑模型和应用程序中的“单一对象疾病”: 单个对象的迭代和立即加载/保存:业务层主要使用 Load/Save() 方法来处理单个对象和少量基于批量/集合的操作。一个常见的工作是通过 SQL 或者它的 NHibernate 表示来获取对象 ID,然后遍历所有检索到的 Id 并以foreach (oneId in Ids) { myObjects.Add( BizModel.GetMyObjectById(oneId) ); }
. 这包括所有元数据、依赖对象集合等,这是典型的 SELECT N+1 情况。此外,大多数 NHibernate …
nosql document-oriented orm relational-theory denormalization
我想要做的是检查列的值是否等于某个字符串,但不区分大小写。在ilike
不使用通配符(百分比)和lower()
? 的情况下使用时是否存在性能差异?
我打算在上创建索引lower(column_name)
并使用lower(column_name) = value
(值已经是小写的),但结果证明我使用的 ORM 不允许我以lower()
漂亮的方式使用(但有方便的方法ilike
)。会column_name ilike 'value'
使用lower(column_name)
索引吗?
这是我的代码:
class csvimportt(Base):
__tablename__ = 'csvimportt'
#id = Column(INTEGER, primary_key=True, autoincrement=True)
aid = Column(INTEGER(unsigned=True, zerofill=True),
Sequence('article_aid_seq', start=1001, increment=1),
primary_key=True)
Run Code Online (Sandbox Code Playgroud)
我想设置一个从 1000 开始的自动增量值。我该怎么做?
我从播客中听说没有 ORM 可以很好地解决执行计划重用问题。它会导致执行计划缓存增加,从而影响性能。
我是一名有抱负的 DBA(我想说大约 3 年内我就可以申请工作了),目前我是一名程序员。我向我的一位朋友传达了我未来的目标,他是一家规模庞大且快节奏的软件开发公司的敏捷 SCRUM 团队的一员。(SDLC 的核心)。
他表达了他对我职业道路目标的担忧 - 指出由于过去 5 - 7 年 ORM 的增加和发展,大多数软件开发公司的 DBA 都是一个垂死的职位。他说,公司信任程序员,他们中的大多数人有能力完成DBA所做的大部分工作。(存储过程、加密、SQL、备份、ddl、分析等)
任何人都可以讲述一下他们的经历或者他们是否对 DBA 职位有相同的担忧/信念?
我指的是 NHibernate 和那些类型的系统。
为了与本网站的问答格式保持一致 - 如果所有内容都转换为并使用 ORM,并且 DBA 职位不再像过去一两年那样重要,那么将来将会面临哪些问题?
老实说,我承认,除了基础研究之外,我没有 ORM 的第一手经验。我知道这个网站应该供专业人士使用,这就是为什么我觉得那些对这种情况了解更多的人将能够更好地识别顾虑/问题。
对象关系映射(以 ActiveRecord 和 Rails 为例)允许程序员定义模型和删除回调之间的关系。
所以我的问题是:我还需要在我的数据库中定义外键吗?外键是否有其他功能(例如速度?),或者它的唯一功能是保持关系完整性?
orm ×13
performance ×5
postgresql ×3
sql-server ×2
ado.net ×1
erd ×1
foreign-key ×1
index ×1
mysql ×1
nosql ×1
python ×1
sqlalchemy ×1
update ×1