第一个查询:SELECT userid 来自userrole 角色IN(1,2,3) 按用户ID分组 有COUNT(1)= 3 查询时间:0.312秒第二次查询:SELECT t1.userid 来自userrole t1 JOIN userrole t2 ON t1.userid = t2.userid AND t2.roleid = 2 JOIN userrole t3 ON t2.userid = t3.userid AND t3.roleid = 3 AND t1.roleid = 1 查询时间:0.016秒这是对的 . 我提出的加入版本比聚合版本快20倍 .
6. Not simplifying complex queries through views
并非所有数据库供应商都支持视图,但对于那些视图,如果明智地使用它们,它们可以极大地简化查询 . 例如,在一个项目中,我使用generic Party model进行CRM . 这是一种非常强大且灵活的建模技术,但可以导致许多连接 . 在这个模型中有:
Party :人员和组织;
Party Role :这些政党所做的事情,例如雇员和雇主;
Party Role Relationship :这些角色如何相互关联 .
例:
特德是一个人,是党的一个子类型;
Ted有很多角色,其中一个是Employee;
英特尔是一个组织,是党的一个子类型;
英特尔有很多角色,其中一个是雇主;
英特尔雇佣了Ted,这意味着他们各自的角色之间存在关系 .
因此,有五个表连接到Ted与他的雇主 . 您假设所有员工都是人员(而非组织)并提供此帮助者视图:
CREATE VIEW vw_employee AS
SELECT p.title, p.given_names, p.surname, p.date_of_birth, p2.party_name employer_name
FROM person p
JOIN party py ON py.id = p.id
JOIN party_role child ON p.id = child.party_id
JOIN party_role_relationship prr ON child.id = prr.child_id AND prr.type = 'EMPLOYMENT'
JOIN party_role parent ON parent.id = prr.parent_id = parent.id
JOIN party p2 ON parent.party_id = p2.id
select e.first_name, e.last_name
from employee e
where e.start_date >
(select max(ds.transaction_date)
from daily_sales ds
where ds.store_id = e.store_id and
ds.total < 10000)
select e.first_name, e.last_name
from employee e,
(select ds.store_id,
max(s.transaction_date) transaction_date
from daily_sales ds
where ds.total < 10000
group by s.store_id) dsx
where e.store_id = dsx.store_id and
e.start_date > dsx.transaction_date
SELECT
(SELECT TOP 1 SomeValue FROM SomeTable WHERE SomeDate = c.Date ORDER BY SomeValue desc) As FirstVal
,(SELECT OtherValue FROM SomeOtherTable WHERE SomeOtherCriteria = c.Criteria) As SecondVal
FROM
MyTable c
SELECT
s.SomeValue As FirstVal
,o.OtherValue As SecondVal
FROM
MyTable c
LEFT JOIN (
SELECT SomeDate, MAX(SomeValue) as SomeValue
FROM SomeTable
GROUP BY SomeDate
) s ON c.Date = s.SomeDate
LEFT JOIN SomeOtherTable o ON c.Criteria = o.SomeOtherCriteria
30 回答
没有理解数据库并发模型以及它如何影响开发 . 事后很容易添加索引和调整查询 . 但是,在没有适当考虑热点,资源争用和正确操作的情况下设计的应用程序(假设您刚刚阅读的内容仍然有效!)可能需要在数据库和应用程序层中进行重大更改以便以后进行更正 .
没有足够重视管理应用程序中的数据库连接 . 然后你会发现应用程序,计算机,服务器和网络都被阻塞了 .
1. Not using appropriate indices
这是一个相对容易的,但它仍然会一直发生 . 外键应该有索引 . 如果你在
WHERE
中使用一个字段,你应该(可能)有一个索引 . 这些索引通常应该根据您需要执行的查询覆盖多个列 .2. Not enforcing referential integrity
您的数据库可能会有所不同,但如果您的数据库支持参照完整性 - 意味着所有外键都保证指向存在的实体 - 您应该使用它 .
在MySQL数据库上看到这种失败是很常见的 . 我不相信MyISAM支持它 . InnoDB确实如此 . 您会找到使用MyISAM的人或使用InnoDB但未使用它的人 .
更多信息:
How important are constraints like NOT NULL and FOREIGN KEY if I’ll always control my database input with php?
Are foreign keys really necessary in a database design?
Are foreign keys really necessary in a database design?
3. Using natural rather than surrogate (technical) primary keys
自然键是基于(表面上)唯一的外部有意义数据的键 . 常见的例子是产品代码,双字母州代码(US),社会安全号码等 . 代理或技术主键是那些在系统外绝对没有意义的主键 . 它们纯粹是为了识别实体而发明的,通常是自动递增字段(SQL Server,MySQL,其他)或序列(最着名的是Oracle) .
在我看来,你应该 always 使用代理键 . 这些问题出现了这个问题:
How do you like your primary keys?
What's the best practice for primary keys in tables?
Which format of primary key would you use in this situation.
Surrogate vs. natural/business keys
Should I have a dedicated primary key field?
这是一个有争议的话题,你不会得到普遍的同意 . 虽然你可能会发现一些人认为自然键在某些情况下是正常的,但除了可以说是不必要的之外,你不会发现任何对代理键的批评 . 如果你问我,这是一个很小的缺点 .
记住,甚至countries can cease to exist(例如,南斯拉夫) .
4. Writing queries that require DISTINCT to work
您经常在ORM生成的查询中看到这一点 . 查看Hibernate的日志输出,您将看到所有查询都以:
这是一个确保你有时看到人们也这样做的捷径 . 如果你看得太多,那就是一个真正的红旗 . 不是
DISTINCT
是坏的,或者不是编写正确查询的代理或权宜之计 .来自Why I Hate DISTINCT:
5. Favouring aggregation over joins
数据库应用程序开发人员的另一个常见错误是没有意识到可以将多少更昂贵的聚合(即
GROUP BY
子句)与连接进行比较 .为了让您了解这是多么广泛,我在这里多次写过这个主题并且为此付出了很多努力 . 例如:
来自SQL statement - “join” vs “group by and having”:
6. Not simplifying complex queries through views
并非所有数据库供应商都支持视图,但对于那些视图,如果明智地使用它们,它们可以极大地简化查询 . 例如,在一个项目中,我使用generic Party model进行CRM . 这是一种非常强大且灵活的建模技术,但可以导致许多连接 . 在这个模型中有:
Party :人员和组织;
Party Role :这些政党所做的事情,例如雇员和雇主;
Party Role Relationship :这些角色如何相互关联 .
例:
特德是一个人,是党的一个子类型;
Ted有很多角色,其中一个是Employee;
英特尔是一个组织,是党的一个子类型;
英特尔有很多角色,其中一个是雇主;
英特尔雇佣了Ted,这意味着他们各自的角色之间存在关系 .
因此,有五个表连接到Ted与他的雇主 . 您假设所有员工都是人员(而非组织)并提供此帮助者视图:
突然之间,您可以非常简单地查看所需数据,但需要使用高度灵活的数据模型 .
7. Not sanitizing input
这是一个巨大的问题 . 现在我喜欢PHP但是如果你不喜欢它,那么创建易受攻击的网站真的很容易 . 没有什么能比story of little Bobby Tables更好地总结了 .
用户通过URL,表单数据 and cookies 提供的数据应始终被视为敌对和消毒 . 确保你得到你期望的 .
8. Not using prepared statements
编译语句是指编译查询减去插入,更新和
WHERE
子句中使用的数据,然后提供后来 . 例如:VS
要么
取决于您的平台 .
通过这样做,我看到数据库瘫痪了 . 基本上,每次任何现代数据库遇到新查询时,都必须编译它 . 如果它遇到了之前看到的查询,那么您将为数据库提供缓存已编译查询和执行计划的机会 . 通过大量执行查询,您可以为数据库提供相应优化的机会(例如,通过将编译后的查询固定在内存中) .
使用预准备语句还可以为您提供有关某些查询使用频率的有意义的统计信息 .
准备好的语句也可以更好地保护您免受SQL注入攻击 .
9. Not normalizing enough
Database normalization基本上是优化数据库设计或如何将数据组织到表中的过程 .
就在本周,我遇到了一些代码,其中有人破坏了一个数组并将其插入数据库的单个字段中 . 规范化可以将该数组的元素视为子表中的单独行(即一对多关系) .
这也出现在Best method for storing a list of user IDs:
但缺乏正常化有多种形式 .
更多:
Normalization: How far is far enough?
SQL by Design: Why You Need Database Normalization
10. Normalizing too much
这似乎与前一点相矛盾,但正常化与许多事情一样,是一种工具 . 它是达到目的的手段,而不是目的本身 . 我认为许多开发人员忘记了这一点,并开始将“手段”视为“结束” . 单元测试就是一个很好的例子 .
我曾经在一个对客户来说具有巨大层次结构的系统上工作过:
这样你就可以在获得任何有意义的数据之前加入大约11个表 . 这是规范化过程中的一个很好的例子 .
更重要的是,谨慎和考虑的非规范化可以带来巨大的性能优势,但在执行此操作时必须非常小心 .
更多:
Why too much Database Normalization can be a Bad Thing
How far to take normalization in database design?
When Not to Normalize your SQL Database
Maybe Normalizing Isn't Normal
The Mother of All Database Normalization Debates on Coding Horror
11. Using exclusive arcs
独占弧是一种常见错误,其中使用两个或多个外键创建表,其中一个且只有一个外键可以为非空 . Big mistake. 一方面,维护数据完整性变得更加困难 . 毕竟,即使使用引用完整性,也没有任何东西阻止设置这些外键中的两个或多个(尽管有复杂的检查约束) .
来自A Practical Guide to Relational Database Design:
12. Not doing performance analysis on queries at all
实用主义至高无上,特别是在数据库世界中 . 如果你坚持原则,以至于他们已成为教条,那么你很可能会犯错误 . 以上面的聚合查询为例 . 聚合版本可能看起来“不错”,但其性能很糟糕 . 表演比较应该结束辩论(但事实并非如此),但更重要的是:首先喷出这种不明智的观点是无知的,甚至是危险的 .
13. Over-reliance on UNION ALL and particularly UNION constructs
SQL术语中的UNION仅连接全等数据集,这意味着它们具有相同类型和数量的列 . 它们之间的区别在于UNION ALL是一个简单的连接,应尽可能首选,而UNION将隐式执行DISTINCT以删除重复的元组 .
像DISTINCT一样,UNION也有自己的位置 . 有效的应用程序 . 但是如果你发现自己做了很多,特别是在子查询中,那么你可能做错了 . 这可能是一个糟糕的查询构造或设计不良的数据模型迫使你做这些事情的情况 .
UNION,特别是在连接或从属子查询中使用时,可能会削弱数据库 . 尽可能避免使用它们 .
14. Using OR conditions in queries
这似乎无害 . 毕竟,ANDs还可以 . 或者应该可以,对吧?错误 . 基本上是AND条件 restricts 数据集而OR条件 grows 它但不是以适合优化的方式 . 特别是当不同的OR条件可能相交时,从而迫使优化器有效地对结果进行DISTINCT操作 .
坏:
更好:
现在,您的SQL优化器可以有效地将第一个查询转换为第二个查询 . 但它可能不会 . 只是不要这样做 .
15. Not designing their data model to lend itself to high-performing solutions
这是一个难以量化的问题 . 通常通过其效果来观察 . 如果您发现自己正在为相对简单的任务编写粗略的查询,或者查找相对简单的信息的查询效率不高,那么您的数据模型可能很差 .
在某些方面,这一点总结了所有早期版本,但更多的是一个警示性的故事,即执行查询优化等操作通常在第二次完成时首先完成 . 首先,您应该确保在尝试之前拥有良好的数据模型优化性能 . 正如Knuth所说:
16. Incorrect use of Database Transactions
特定过程的所有数据更改都应该是原子的 . 即如果操作成功,则完全如此 . 如果失败,数据保持不变 . - 不应该有“半完成”的变化 .
理想情况下,实现此目的的最简单方法是整个系统设计应努力通过单个INSERT / UPDATE / DELETE语句支持所有数据更改 . 在这种情况下,不需要特殊的事务处理,因为您的数据库引擎应该自动执行 .
但是,如果任何进程确实需要将多个语句作为一个单元执行以使数据保持一致状态,则必须进行适当的事务控制 .
在第一个语句之前开始一个事务 .
在最后一个语句之后提交事务 .
如有任何错误,请回滚事务 . 非常NB!不要忘记跳过/中止错误后面的所有语句 .
还建议您仔细关注数据库连接层和数据库引擎如何在这方面进行交互的子网站 .
17. Not understanding the 'set-based' paradigm
SQL语言遵循适用于特定类型问题的特定范例 . 尽管有各种特定于供应商的扩展,但该语言仍在努力处理Java,C#,Delphi等语言中的微不足道的问题 .
这种缺乏理解在某些方面表现出来 .
在数据库上不恰当地施加过多的程序或命令逻辑 .
不当或过度使用游标 . 特别是当单个查询就足够了 .
错误地假设在多行更新中每行触发一次触发器 .
确定明确的责任分工,并努力使用适当的工具来解决每个问题 .
当他们在这些领域没有任何形式的正式灌输时,他们认为他们是DBA和数据建模师/设计师 .
认为他们的项目不需要DBA,因为这些东西都很容易/琐碎 .
无法正确识别应在数据库中完成的工作与应在应用程序中完成的工作 .
未验证备份或未备份 .
在其代码中嵌入原始SQL .
以下是Scott Walz撰写的名为“Classic Database Development Mistakes and five ways to overcome them”的视频链接
Key database design and programming mistakes made by developers
Selfish database design and usage. 开发人员经常将数据库视为其个人持久对象存储库,而不考虑数据中其他利益相关者的需求 . 这也适用于应用程序架构师 . 糟糕的数据库设计和数据完整性使第三方难以处理数据,并且可能大大增加系统的生命周期成本 . 报告和MIS往往是应用程序设计中的一个表兄弟,只是在事后才做好 .
Abusing denormalised data. 过度使用非规范化数据并尝试在应用程序中维护它是数据完整性问题的一个方法 . 谨慎使用非规范化 . 不希望向查询添加连接不是非规范化的借口 .
Scared of writing SQL. SQL不是火箭科学,实际上非常擅长完成它的工作 . O / R映射层非常擅长95%的简单查询并且非常适合该模型 . 有时SQL是完成这项工作的最佳方式 .
Dogmatic 'No Stored Procedures' policies. 无论您是否认为存储过程是邪恶的,这种教条式的态度在软件项目中都没有 .
Not understanding database design. 规范化是你的朋友,它是not rocket science.加入和基数是相当简单的概念 - 如果你真的没有理由不理解它们 .
未在数据库模式上使用版本控制
直接针对实时数据库
没有阅读和理解更高级的数据库概念(索引,聚簇索引,约束,物化视图等)
未能测试可扩展性...只有3行或4行的测试数据永远不会给你真实的现场表现
过度使用和/或依赖存储过程 .
一些应用程序开发人员将存储过程视为中间层/前端代码的直接扩展 . 这似乎是Microsoft堆栈开发人员的一个共同特征(我只是一个,但我已经成长了),并生成了许多执行复杂业务逻辑和工作流处理的存储过程 . 其他地方要好得多 .
在已经证实某些真正的技术因素需要使用它们(例如,性能和安全性)的情况下,存储过程是有用的 . 例如,保持大数据集的聚合/过滤“接近数据” .
我最近不得不帮助维护和增强一个大型Delphi桌面应用程序,其中70%的业务逻辑和规则是在1400个SQL Server存储过程中实现的(其余部分在UI事件处理程序中) . 这是一场噩梦,主要是因为对TSQL引入有效的单元测试,缺乏封装和糟糕的工具(调试器,编辑器) .
过去与Java团队合作我很快发现在这种环境中通常完全相反 . Java架构师曾告诉我:“数据库用于数据,而不是代码 . ”
这些天我认为根本不考虑存储过程是错误的,但是在它们提供有用的好处的情况下应该谨慎使用它们(不是默认)(参见其他答案) .
头号问题?他们只测试玩具数据库 . 所以他们当数据库变大时,他们不知道他们的SQL会爬行,而且有人必须在以后修复它(你听到的声音就是我的牙齿磨损) .
不使用索引 .
Poor Performance Caused by Correlated Subqueries
大多数情况下,您希望避免相关子查询 . 如果子查询中存在对外部查询中的列的引用,则子查询是相关的 . 发生这种情况时,对于返回的每一行,子查询至少执行一次,如果在应用包含相关子查询的条件后应用其他条件,则子查询可执行多次 .
原谅人为的例子和Oracle语法,但是假设你想找到自从上一次商店每天销售额低于10,000美元以来在所有商店雇用的所有员工 .
此示例中的子查询通过store_id与外部查询相关联,并将为系统中的每个员工执行 . 可以优化此查询的一种方法是将子查询移动到内联视图 .
在此示例中,from子句中的查询现在是内联视图(同样是某些Oracle特定语法),并且只执行一次 . 根据您的数据模型,此查询可能会执行得更快 . 随着员工数量的增长,它的表现将优于第一个查询 . 如果很少有员工和许多商店(也许许多商店没有员工)并且daily_sales表在store_id上编入索引,那么第一个查询实际上可以更好地执行 . 这不是一种可能的情况,但显示了相关查询如何比替代查询更好地执行 .
我见过初级开发人员多次关联子查询,它通常会对性能产生严重影响 . 但是,在删除相关子查询时,请确保在之前和之后查看explain plan,以确保不会使性能变差 .
在我的经验中:
不与经验丰富的DBA沟通 .
使用Access而不是"real"数据库 . 有很多很棒的小型甚至是免费的数据库,比如SQL Express,MySQL和SQLite,它们可以更好地工作和扩展 . 应用通常需要以意想不到的方式扩展 .
忘记在表之间 Build 关系 . 我记得当我刚开始在现任雇主工作时必须清理它 .
使用Excel存储(大量)数据 .
我见过公司持有数千行并使用多个工作表(由于以前版本的Excel的行限制为65535) .
Excel非常适合报表,数据表示和其他任务,但不应将其视为数据库 .
我想补充一点:在高性能代码上偏爱“优雅”代码 . 对应用程序开发人员来说,最适合数据库的代码通常很难看 .
相信过早优化的废话 . 数据库必须考虑原始设计和任何后续开发中的性能 . 在我看来,性能是数据库设计的50%(40%是数据完整性,最后10%是安全性) . 一旦真实用户和真实流量对数据库放置,那么从下到上执行的数据库将执行不良 . 过早优化并不意味着没有优化!这并不意味着您应该编写几乎总是表现不佳的代码,因为您会发现它更容易(例如,除非所有其他方法都失败,否则永远不应该在 生产环境 数据库中使用游标) . 这意味着在您需要之前,您不需要考虑挤出最后一点性能 . 关于什么在数据库上表现更好,众所周知,在设计和开发中忽略这一点充其量是短视的 .
不使用参数化查询 . 他们在停止SQL Injection时非常方便 .
这是另一个答案中提到的不清理输入数据的具体示例 .
当开发人员使用嵌套的select语句甚至函数时,我讨厌在查询的“SELECT”部分内返回select语句的结果 .
我真的很惊讶我在这里其他任何地方都没有看到这个,也许我忽略了它,尽管@adam也有类似的问题 .
例:
在这种情况下,如果MyTable返回10000行,结果就好像查询只运行了20001个查询,因为它必须运行初始查询并为每行结果查询每个其他表一次 .
开发人员可以在开发环境中工作,他们只返回几行数据,子表通常只有少量数据,但在 生产环境 环境中,这种查询可能会成倍增加成本数据被添加到表中 .
一个更好(不一定完美)的例子是这样的:
这允许数据库优化器将数据混合在一起,而不是从主表中重新查询每条记录,而我通常会在必须修复已创建此问题的代码,我通常最终会将查询速度提高100%或更多,同时减少CPU和内存使用量 .
对于基于SQL的数据库:
未利用CLUSTERED INDEXES或选择错误的列到CLUSTER .
未使用SERIAL(autonumber)数据类型作为PRIMARY KEY加入父/子表关系中的FOREIGN KEY(INT) .
当许多记录被INSERTED或DELETED时,不更新表上的统计信息 .
在插入或删除了许多行时,不重组(即卸载,删除,重新创建,加载和重新编制索引)表(某些引擎在物理上将删除的行保留在带有删除标记的表中 . )
在具有高事务率的大型表上不利用FRAGMENT ON EXPRESSION(如果支持) .
为列选择错误的数据类型!
未选择正确的列名 .
不在表的末尾添加新列 .
未创建正确的索引以支持常用查询 .
在具有少量可能值的列上创建索引并创建不必要的索引 .
......还有更多要补充 .
在修复 生产环境 数据库中的某些问题之前未进行备份 .
在存储过程中对存储对象(如表,视图)使用DDL命令 .
害怕使用存储过程或害怕使用ORM查询,无论哪个更有效/适合使用 .
忽略数据库分析器的使用,它可以告诉您最终将ORM查询转换为什么,从而验证逻辑,甚至在不使用ORM时进行调试 .
没有做正确的normalization级别 . 您希望确保数据不重复,并且您要根据需要将数据拆分为不同的数据 . 你还需要确保你没有遵循规范化,因为这会损害性能 .
将数据库视为一种存储机制(即美化的集合库),从而从属于其应用程序(忽略共享数据的其他应用程序)
由于"it's too magical"或“不在 my 数据库”等原因而无法解除像Hibernate这样的ORM .
过分依赖像Hibernate这样的ORM,并试图在不合适的地方进行操作 .
1 - 不必使用where子句中的值的函数,并且未使用该索引的结果 .
例:
代替
在较小程度上:不向那些需要它们的值添加功能索引......
2 - 不添加检查约束以确保数据的有效性 . 查询优化器可以使用约束,它们确实有助于确保您可以信任不变量 . 没有理由不使用它们 .
3 - 在纯粹的懒惰或时间压力下向表格添加非标准化列 . 事情通常不是这样设计的,而是演变成这个 . 最终的结果是,当你在未来的演变中被丢失的数据完整性所困扰时,试图清理混乱的大量工作 .
想一想,没有数据的表是非常便宜的重新设计 . 一张表有几百万条没有完整性的记录...重新设计不那么便宜 . 因此,在创建列或表时执行正确的设计将在黑桃中摊销 .
4 - 与数据库本身不是很多,但确实很烦人 . 不关心SQL的代码质量 . 您的SQL以文本表达的事实并不能将逻辑隐藏在字符串操作算法的堆中 . 完全可以以一种实际上可由您的程序员读取的方式在文本中编写SQL .
之前已经说过,但是: indexes, indexes, indexes . 我甚至不需要SQL写作知识,而且收益很大 .
避免像瘟疫一样的数据重复 . 有些人主张一点点重复不会伤害,并会提高性能 . 嘿,我不是说你必须将你的模式折磨成第三范式,直到它如此抽象,甚至连DBA都不知道发生了什么 . 只需理解,无论何时复制一组名称,邮政编码或运输代码,副本最终都会彼此不同步 . 它会发生 . 然后,当您运行每周维护脚本时,您将自己踢 .
最后:使用清晰,一致,直观的命名约定 . 就像编写良好的代码片段应该是可读的一样,一个好的SQL模式或查询应该是可读的,并且几乎可以告诉你在六个月内你需要对表进行维护的时候会感谢你自己.788319_感谢你自己 .
"SELECT account_number, billing_date FROM national_accounts"
比"SELECT ACCNTNBR, BILLDAT FROM NTNLACCTS"更容易使用 .在运行DELETE查询之前不执行相应的SELECT查询(特别是在 生产环境 数据库上)!
我二十年来见过的最常见的错误:不是提前计划 . 许多开发人员将创建数据库和表,然后在构建应用程序时不断修改和扩展表 . 最终结果往往是混乱,效率低下,以后难以清理或简化 .
a)字符串中的硬编码查询值
b)将数据库查询代码放在Windows窗体应用程序的"OnButtonPress"操作中
我见过两者 .
Not understanding how a DBMS works under the hood.
如果不了解离合器的工作原理,就无法正确驾驶 . 如果不了解您实际上只是写入硬盘上的文件,就无法理解如何使用数据库 .
特别:
你知道聚集指数是什么吗?您在设计架构时是否考虑过这个问题?
您知道如何正确使用索引吗?如何重用索引?你知道覆盖指数是什么吗?
太好了,你有索引 . 索引中的1行有多大?当您拥有大量数据时索引有多大?这容易适合记忆吗?如果它不会作为索引无用 .
你曾经在MySQL中使用过EXPLAIN吗?大 . 现在对自己说实话:你有甚么了解你看到的一半吗?不,你可能没有 . 修复它 .
您了解查询缓存吗?你知道是什么让查询无法访问吗?
您使用的是MyISAM吗?如果你需要全文搜索,MyISAM无论如何都是垃圾 . 使用Sphinx . 然后切换到Inno .
使用ORM进行批量更新
选择超出需要的数据 . 同样,通常在使用ORM时完成
在循环中解冻sqls .
没有良好的测试数据,只注意到实时数据的性能下降 .