设为首页 加入收藏

TOP

数据库设计的7个常见错误(二)
2015-11-21 01:27:12 来源: 作者: 【 】 浏览:3
Tags:数据库 设计 常见 错误
注意,不同数据库对于可变长的字符和文本字段会有不同的限制。举些例子:
?
前面提到过,Oracle对varchar类型的列有4000个字节限制。
?
Oracle将低于4KB的CLOB直接存储到表中,这种数据访问起来如同任何varchar列一样快。但大些的CLOB读取时就会耗时变长,因为它们存在表的外面。
?
PostgreSQL允许一个未限制长度的varchar列存储甚至是千兆字节的字符串,且是默默地把字符串存到后台表,不会降低整个表的性能。
提示:
?
一般而言,考虑到安全和性能,数据库中限制文本列的长度是好的,但有时这个做法可能没有必要或者不方便;
?
不同的数据库对待文本限制可能会有差异;
?
使用英语以外的语言时永远记住编码。
?
下面是把book_comment的评论类型修改为text后的模型:
模型中修改的地方如下图:
3 ——没有恰当地添加索引
?
有一个说法是“伟大是实现的,而不是被赠与的”。这个说法同样可以用在性能上——通过精心设计数据库模型,优化数据库参数以及优化数据库应用查询来实现。当然这里我们关注的是模型设计。
?
在例子中,我们假定书城的GUI设计者决定在首页显示最新的30条评论。为了查询这些评论,我们将使用如下的语句:
?
select comment, send_ts from book_comment order by send_ts desc limit 30;
这个查询运行起来有多快?在我的笔记本上花费不到70毫秒。但是如果我们希望应用能够按比例变化(在高负载下快速运行),需要在更大的数据上检测。所以我在book_comment表中插入了更多的记录。为此我将使用一个很长的单词列表,然后使用一个简单的Perl命令将其转成SQL。
?
现在我要把这个SQL导入到PostgreSQL数据库。一旦导入开始,我就会检测之前那个查询的执行时间。统计结果在如下的表格中:
如你所见,随着 book_comment 中行数的增加,要获取最新30行所花费的查询时间也在成比例地增加。为何耗费时间增长?我们看看这个查询计划:
?
db=# explain select comment, send_ts from book_comment order by send_ts desc limit 30;
? ? ? ? ? ? ? ? ? ? ? ? ? ? QUERY PLAN ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
-------------------------------------------------------------------
?Limit ?(cost=28244.01..28244.09 rows=30 width=17)
? ?-> ?Sort ?(cost=28244.01..29751.62 rows=603044 width=17)
? ? ? ? ?Sort Key: send_ts
? ? ? ? ?-> ?Seq Scan on book_comment ?(cost=0.00..10433.44 rows=603044 width=17)
?
这个查询计划告诉我们数据库如何处理查询及计算结果的大致时间成本。这里PostgreSQL告诉我们将进行“Seq Scan on book_comment”,这意味着它将逐个检查 book_comment 表的所有记录,以此对send_ts列的值进行排序。貌似PostgreSQL还没有聪明到在不去对所有的600,000条进行排序的条件下查询30个最新记录。
?
幸运地是,我们可以通过告知PostgreSQL根据send_ts进行排序并保存结果来帮助它。为此,我们先在该列上创建一个索引:
?
create index book_comment_send_ts_idx on book_comment(send_ts);
?
现在我们的查询语句从600,000条记录中查询出最新30条所花费的时间又是67毫秒了。查询计划差别非常大:
?
db=# explain select comment, send_ts from book_comment order by send_ts desc limit 30;
? ? ? ? ? ? ? ? ? ? ? ? ? ?QUERY PLAN ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
--------------------------------------------------------------------?
Limit ?(cost=0.42..1.43 rows=30 width=17)
? ?-> ?Index Scan Backward using book_comment_send_ts_idx on book_comment ?(cost=0.42..20465.77 rows=610667 width=17)
?
“Index Scan”指不是逐行扫描book_comment表,而是数据库会扫描我们刚刚创建的索引。估计查询成本小于1.43,低于之前的2.8万倍。
?
你遇到了性能问题?第一次尝试解决就应当是找到运行时间最长的查询,让你的数据库来解释它们,并且寻找全表扫描。如果你找到了,也许增加一些索引可以快速提升速度。
?
不过,数据库性能设计是一个庞大的主题,超出了本文的范围。
?
我们在如下提示中列出一些重要的方面。
?
提示:
?
经常检查运行时间长的查询,或许可以用上EXPLAIN功能;大多数现代数据库都有该功能;
?
在创建索引时:
?
记住它们不会一直被用到;数据库如果计算出使用索引所耗费的时间长于全表扫描或其它操作时,将不会使用索引;
?
记住使用索引带来的代价是——在被索引的表上INSERT和DELETE会变慢
?
如果需要索引请考虑非默认类型的索引;如果你的索引工作得不是很好,请查阅数据库手册;
?
有时候你需要优化查询,而不是模型;
?
不是每一个性能问题都可以通过创建一个索引来解决;有很多其它解决性能问题的方式;
?
各个应用层的缓存,
?
调优数据库参数和缓冲区大小,
?
调优数据库连接池大小或者线程池大小,
?
调整数据库事务隔离级别,
?
在夜间安排批量删除,避免不必要的锁表,
?
其它等等。
?
在book_comment.send_ts列上带有索引的模型如下:
4 ——没有考虑到可能的数据量或流量
?
通常你可以得到有关可能的数据量的附加信息。如果你正在构建的系统是另一个已存在项目的迭代,你可以通过查看老系统的数据量来计算出系统数据的预期大小。
?
如果你的书城非常成功,purchase表的数据量可能会非常大。你卖得越多,purchase表里的数据行数增加越多。假如你事先知道这一点,你可以把当前已处理的订单与完成的订单分开。你可以用两个表:purchase表记录当前的订单,archived_purchase表记录完成的订单,而不是用一张单
首页 上一页 1 2 3 4 下一页 尾页 2/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇外键值可为空 下一篇centos+scala2.11.4+hadoop2.3+sp..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: