设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

PostgreSQL vs. MS SQL Server

2014-12-3 11:24| 发布者: joejoe0332| 查看: 6960| 评论: 0|原作者: 开源中国七里香, 几点人, BreakinBad, daxiang, MagicBLS, 无若, 台阶|来自: oschina

摘要: 这些年里,我已经太多太多次的讨论了 PostgreSQL 和 MS SQL 的问题。IT 行业中一个知名的原则说:如果你准备不只一次的做同一件事,那就让它自动化。本文是我的自动化方法的谈话。 ... ...


你能够在Linux,BSD等平台上运行PostgreSQL(当然,在Windows上也可以)

  IT行业的开发人员都清楚跨平台是当今一个关注点。支持跨平台可以说是Java杀手级的特性,其实Java是一门尚显粗糙、丑陋的编程语言,但它依然获得了巨大的成功,广泛的影响及普及。Linux与苹果的崛起使微软在桌面领域无法再保持垄断地位。云服务的灵活性和高性能虚拟化技术的易访问性,使IT基础设施越来越多样化。跨平台软件能够提供给用户控制他们的基础设施。(工作中,我目前管理着好几个PostgreSQL 数据库,一些运行在Windows平台上,一些在Ubuntu Linux上。我和同事自由地在这些平台之间移动代码和数据库数据。我们使用Python和PHP,因为他们在两种操作系统上都能运行。它们全部运行得很好。)


  微软的政策一直都是供应商锁定。 他们不开放自己的代码;他们不提供跨平台版本的软件;他们甚至自己创造一个完整的生态系统,.NET设计用于为微软用户和非微软用户搭建了一座桥梁。 这对他们是有利的,因为这种方式保证了他们的利润。 这对你(用户)是不利的,因为微软限制了你的选择,而且为你创建了一些不必要的工作。


  这不是一篇对比 Linux和 Windows的文档,尽管我确定我最后会提到几点。  可以肯定地说,对于真正的 IT工作, Linux(和类 UNIX操作系统家族: Solaris, BSD等)把 Windows甩出几条街。  类 UNIX操作系统主宰着服务器市场、云服务、超级计算(在这个领域它近乎垄断)和科学计算,一个原因就是 - 这些系统是技术人员为技术人员设计的。 最终,他们以巨大的力量和灵活性换得了用户友好性。 一个合格的类 UNIX OS 不仅仅是一个漂亮的命令行集合 – 它是一个包含各种程序、实用工具、功能的生态系统,并且提供支持使完成工作变得高效和有趣。 一个合格的 Linux黑客可以用一行被抛弃的 Bash脚本达到目的,但是这个任务在 Windows中是艰巨且耗时的。


  (例如,某一天,我在查看朋友影片收集情况,他对我说,他认为他的文件系统中文件的总数量太多,他想知道究竟有多少影片文件,还想知道他是否可还以把一个大型的文件夹结构复制到影片文件夹下。我使用下面语句对每个文件夹及其子文件夹所包含文件数进行了计算: 

1
find . -type f | awk 'BEGIN {FS="/";} {print $2;}' | sort | uniq -c | sort -rn | less


  整件事情做下来编写花了一分钟,运行花了一秒钟。同时还证实某些文件夹有问题,并告诉他具体哪个文件夹有问题。Windows下怎么能做到这些呢?)


  在做数据分析时,关系型数据管理系统(RDBMS)不可能处在真空里;它是整套工具中一部分。因此它所处的环境就非常重要。MS SQL服务器只可在Windows系统上使用,而Windows是一个很差劲的可用于分析的环境。


1.4程序语言特性

  这可是一个大问题。


  一个“纯”字可以概括SQL,因为它只专注于它被设计的初衷,那就是关系型数据的操作和查询。如果你尝试用它做更多的分析处理的话,比如复杂的利息计算、时间序列分析以及通用算法设计,你将很快达到它的极限。SQL数据库的提供者对这些比较了解,所以几乎所有的SQL数据库都实现了某种程序语言。这就是使得数据库用户可以写命令式风格的代码以用于更复杂或繁琐的任务。


  PostgreSQL的程序语言支持比较好。对它来说在一个小范围内是不可能做到公正的,不过这只是一个样本。这些程序语言的任何一个都可以用来写存储过程和函数或直接转储到一个内联执行的代码块。


  • PL/PGSQL: 它是PostgresSQL 原生的程序语言。 它与Oracle的PL/SQL类似,但是它比后者更现代、功能更完善。

  • PL/V8:来自Google Chrome的V8脚本引擎在PostgresSQL中可以使用。 这个引擎稳定、功能丰富、速度不可思议地快 – 经常接近于经过优化和编译的C语言代码的执行速度。把它和PostgresSQL对JSON数据类型的原生支持结合起来(见下文),在一个单独的包中你会有终极的力量和灵活性。甚至更好,PL/V8支持全局(跨函数调用,等等)状态,允许用户选择性地快速随机访问RAM中高速缓存数据。 假设表A有100,000行数据,表B有1,000,000行数据,对于表B中的每行数据都需要与表A中所有数据进行关联。 使用传统的SQL,你要么需要关联这两张表(在中间表中会有10^11行数据,这会累死所有计算机,除最强大计算机外)或者进行一个类似于标量的子查询(或者使用基于游标的嵌套循环,这更糟),如果查询解析器没有正确地读懂你的意图,这些方法会带来沉重的I/O负担。在PL/V8中,你只需在内存中缓存表A的数据,遍历表B的数据时调用一个函数 – 访问这个有100,000行的表A时,它会给你RAM级别的访问速度(微不足道的延迟和随机访问惩罚;没有非易失性I/O加载)。 最近我在我的一个项目中使用了这种方法- 我的PostgreSQL/PLV8代码运行速度比微软T-SQL解决方法快80倍,并且代码更简洁、更易维护。 由于运行耗时23秒而不是30分钟,我因此能够在1个小时内完成20个测试周期(运行-测试-修改),从而写出功能完善、经过测试、无bug的代码。 关于这一点,在这里可以看到更多细节。(由于使用 DROP SCHEMA CASCADE,并且在批量声明中间可以随意执行CREATE FUNCTION语句,所有那些测试周期才是可能完成的,正如上面解释的那样。 看它们在一起是多么搭配啊!)


  • PL/Python:你可以在PostgreSQL里随意使用Python。Python2或者Python3,随你选,都可以,你可以使用大量的Python库,Python正是因为它们才出名的。在SQL查询语句中间想调用scikit-learn提供的SVM或者gmpy2提供的某些任意精度的算法,可以吗?没问题!

  • PL/Perl:Perl已经不流行一段时间了,不过因其功能多而赢得了编程语言瑞士军刀的美誉。在PostgreSQL里,你完全可以把Perl用做编写存储过程语言。

  • PL/R:R是学术和数据科学领域统计编程的事实标准,而且还有很好的理由使用它-它免费、强大、功能全面,同时有大量高质量的插件和附件库支持。因此PostgreSQL允许你可以使用R做为编写存储过程的语言。

  • 在PostgreSQL里,还可以用Java、Lua、sh、Tcl、Ruby和PHP做为编写存储过程的语言。

  • C:它确实不属于存储过程语言列表,因为你需要单独对它进行编译,不过在这儿值得一提。在PostgreSQL中,可以非常容易地创建在数据库后台进程里进行C(或者C++或者汇编) 的编译、优化的函数。这是一个非常强大的用户功能,它可以让哪些对性能有特别要求的任务运行速度最快、内存管理和资源利用得到精确地控制。我已经用它实现了复杂的支付状态处理算法,可在一秒钟操作一百万行数据-而且是在桌面PC上运行的。


  MS SQL Server 内置的面向过程编程语言 (T-SQL 对 SQL 扩充的一部分) 既笨拙, 又缓慢, 各种缺点。 就如 Microsoft 自己的文档的那样, 它有时会容易产生一些奇怪的错误和 Bug。  我还没见过哪个程序员说他喜欢 T-SQL 的。


  那放到 MS SQL Server 上面用的 .NET 组件呢 ?  这种不算面向过程语言支持, 因为你不能直接向数据库引擎提交代码。要知道, 可管理性和人类工程学(ergonomics )都很重要。 直接将 Python 代码嵌入数据库查询语句中, 既简单又方便; 启动 Visual Studio, 然后管理一堆项目,复制一堆 DLL 文件 (都是在图形用户界面中处理的,不能很好的脚本化,版本控制, 自动化, 以及审查 )其实挺尴尬的,而且容易出错,扩展性又不好。总之, 这种机制在很大程度上受限于.NET 语言。


1.5支持原生正则表达式

正则表达式(regexen或者regexes)对于分析工作来说就像会算术一样的基础,对于大量的文本处理任务来说它们是首选(经常是唯一选择)。不支持正则表达式的数据分析工具就像一个没有座的自行车一样,你仍然可以用它,但是充满痛苦(菊花都残了当然痛—译者加)。

PostgreSQL有开箱即用的正则表达式支持。看几个例子:

取得所有以重复数字并且紧跟元音字母开头的行:

1
SELECT FROM my_table WHERE my_field ~ E'^([0-9])\\1+[aeiou]';

取得某一个字段中第一个出现的单独的十六进制字符串:

1
SELECT SUBSTRING(my_field FROM E'\\y[A-Fa-f0-9]+\\y'FROM my_table;

将一个 字符串以空白字符分割,并且以单行的形式返回每一部分:

1
2
3
4
5
6
7
8
9
SELECT REGEXP_SPLIT_TO_TABLE('The quick brown fox', E'\\s+');
-- Returns this:
 
-- | column |
-- -----------
-- | The    |
-- | quick  |
-- | brown  |
-- | fox    |

查找一个字符串中最少有10个字母的单词(不区分大小写):

1
SELECT REGEXP_MATCHES(my_string, E'\\y[a-z]{10,}\\y''gi'FROM my_table;


  MS SQL Server有 LIKE ,SUBSTRING,PATINDEX 等等,不过它们与恰当的正则表达式支持不具可比性(如果你对此怀疑,你可以尝试使用它们来实现上面的例子)。有第三方的库可用于MS SQL Server,它们不像PostgreSQL的支持那样好,并且获取和安装它们会增进管理开销。


  还要注意到PostgreSQL的支持扩展程序语言特性也让你有好几个其他的正则表达式引擎可用,当然也包括它们的各种特性。比如Python的正则库提供的对正向和负向后行断言的支持。这正符合PostgreSQL的一贯作风,给你干好工作的所有你需要的工具。


1.6自定义聚合函数

  这是一个PostgreSQL和MS SQL Server两者都提供的一个技术上的特性。不过,在实现上却有巨大的不同。


  在PostgreSQL中,自定义聚合很方便并且使用简单,产生了可以快速解决问题和可维护的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
CREATE FUNCTION interest_sfunc(state JSON, movement FLOAT, rate FLOAT, dt DATERETURNS JSON AS
$$
state.balance += movement;  //payments into/withdrawals from account
if (0 === dt.getUTCDate()) //compound interest on 1st of every month
{
  state.balance += state.accrual;
  state.accrual = 0;
}
state.accrual += state.balance * rate;
return state;
$$ LANGUAGE plv8;
 
CREATE AGGREGATE interest(FLOATFLOATDATE)
(
  SFUNC=interest_sfunc,
  STYPE=JSON,
  INITCOND='{"balance": 0, "accrual": 0}'
);
 
--assume accounts table has customer ID, date, interest rate and account movement for each day
CREATE TABLE cust_balances AS
SELECT
  cust_id,
  (interest(movement, rate, dt ORDER BY dt)->>'balance')::FLOAT AS balance
FROM
  accounts
GROUP BY
  cust_id;


  简单吧?自定义的聚集函数主要关注的是内部的状态和我们输入新值给这个聚集函数时修改这个状态的方法。在这个例子里,我们假设一开始每个客户的余额为零,而且累计利息也为零,接着我们每天适当地进行利息累计,并对每天的支付和撤消记账。在每个月的1号,我们进行利息复合。注意:这个聚集函数接纳ORDER BY子句(因为它与SUMMAXMIN不同,它是排序相关的),另外PostgreSQL有操作符可以从JSON对象里提取对应的数值。因此,我们在28行代码里创建了每月对银行账户进行利息复合的框架,使用这个框架就可以计算出最终的账户余额。如果打算给这个方法增添功能(比如根据借/贷额度进行利率修改,异常检测),这一切都可以在转换函数里实现,只要采用适合于实现复杂逻辑的语言编写即可。(不幸的是:我看到许多组织机构使用较差的工具花费数万英镑经过数周的努力试图完成同样的任务。)


  而MS SQL 服务器要实现这样的任务就异常困难


  顺带说明一下,上面的第二个链接里的例子实现了简单的字符串连接聚集。注意:实现如此简单的功能需要大量的代码和技巧(而PostgreSQL内部提供了此功能,随拿随用。这可能是因为这个功能有用!)MS SQL服务器还禁止在聚集函数里指定排序,使用这样的函数无法完成我现在要完成的任务-在MS SQL服务器里,字符串连接的顺序是随机的,因此使用这个函数查询的结果就是无法确定的(即每次运行结果都可能不同),而且这样的代码也不会通过质量审查的。


  缺乏排序支持还可能使得以前编写的代码无法运行,比如上面计算利息的例子。正如我所说,你无法通过使用MS SQL服务器自定义的聚集函数完成当前的任务。


  (实际上,可以让MS SQL服务器使用纯SQL语句实现结果可以确定的字符串连接聚集,不过,你需要多次使用RECURSIVE查询功能来实现。虽然可以把它当作一次有趣的学术性练习,但是这会生成运行速度慢、无法阅读且无法维护的代码,因此它不是一个可以使用在现实世界的解决方案。)


 


酷毙

雷人
1

鲜花

鸡蛋

漂亮

刚表态过的朋友 (1 人)

  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部