美文网首页设计数据密集型应用
《设计数据密集型应用》第二章(2) 查询语言

《设计数据密集型应用》第二章(2) 查询语言

作者: MeazZa | 来源:发表于2018-01-30 10:27 被阅读0次

    本节继续介绍关于数据查询语言(Query Languages)相关的内容。

    查询语言

    数据查询,通常可以由两种方式来实现:

    • 描述性语言

    描述性语言中最常见的例子就是SQL,它是可以通过写一条类似英文句子的SQL表达式,将用户的查询需求描述出来。例如,我们有一系列的生物物种,想从其中找到所有的鲨鱼:

    SELECT * FROM animals WHERE family = 'Sharks';
    

    描述性语言告诉计算机,以特定的顺序来执行特定的操作,而不必关心实现的细节。

    • 命令式语言

    命令式语言即我们通常写的代码,它是通过明确的将查询过程,用代码表达式写出,来进行数据查询的操作。比如上述的例子,用命令式语言写出的代码如下所示:

    function getSharks() {
        var sharks = [];
        for (var i = 0; i < animals.length; i++) {
            if (animals[i].family === "Sharks") {
                sharks.push(animals[i]);
            }
        }
        return sharks;
    }
    

    描述性语言,将数据库引擎在查询时,具体的执行细节隐藏起来。因此,可以在不修改查询语言的情况下,通过查询优化器对索引和关联方法等的优化,提高查询性能。同样,现在计算机的CPU核数不断增加,使用命令式语言编写多线程执行的代码并不容易。而描述性语言,因为仅指定了想要结果的模式,可以由查询优化器来完成并行查询的实现。

    MapReduce查询

    MapReduce是由Google提出的通过使用多台机器处理大量数据的模型。MapReduce本质上是介于描述性语言和命令式语言之间的,map和reduce的函数,是由命令式的代码段实现具体的查询逻辑,map-reduce的数据之间的传输,是由MapReduce框架来实现的。目前NoSQL数据库,比如MongoDB,已经可以支持部分MapReduce查询的模式。
    这里假设一个查询场景,一个海洋生物学家,记录了每次观测到的动物,现在想查询在记录中每月观察到的鲨鱼的数量,用PostgreSQL写出的查询语句如下所示:

    SELECT
        date_trunc ('month', observation_timestamp) AS observation_month, // 这里
        sum(num_animals) AS total_animals
    FROM
        observations
    WHERE
        family = 'Sharks'
    GROUP BY
        observation_month;
    

    相同查询使用MongoDB的MapReduce特性,表达式如下:

    db.observations.mapReduce(
        function map() { // 2. javascript写的map方法,对每个文档都调用一次
            var year = this.observationTimestamp.getFullYear();
            var month = this.observationTimestamp.getMonth() + 1;
            emit(year + "-" + month, this.numAnimals); // 3. map发出一个日期和动物数的键值对
        },
        function reduce(key, values) { // 4. 键值对按照键聚合,对于所有相同键的键值对,调用一次reduce方法
            return Array.sum(values); // 5. reduce方法将所有的动物数相加
        }, {
            query: {family: "Sharks"}, // 1. 使用filter过滤属于鲨鱼的数据
            out: "monthlySharkReport" // 6. 结果写入新的表中
        }
    );
    

    这里的map和reduce方法是有一定限制的。它们比如是纯函数(pure functions),也就是它们只允许使用传入到它们的数据,而不允许进行额外的数据库查询,引起任何负效应。这个限制可以使得数据库可以在任何时间,任何地点,以任意的顺序执行这些方法,并且在执行失败的时候重新运行。

    上述的查询使用还是比较低层次的变成模型,MongoDB在2.2版本支持了一种描述性查询语言,聚合流水线(aggregation pipeline),相同的查询可以通过以下方式表达:

    db.observations.aggregate([{
        $match: {
            family: "Sharks"
        }
    }, {
        $group: {
            _id: {
                year: {$year: "$observationTimestamp"},
                month: {$month: "$observationTimestamp"}
            },
            totalAnimals: {
                $sum: "$numAnimals"
            }
        }
    }]);
    

    总结

    数据的查询方式,主要有描述性语言和命令式语言两种。描述性语言即我们常说的SQL,它可以通过一些特定的语法,描述出用户想要查询的数据结果;命令式语言一般通过代码来实现,查询的具体执行过程完全依赖于代码。
    对于常规数据产品开发来说,使用SQL是一个主流方式,因为可以将查询的具体执行细节交给数据库引擎来实现,并且在切换底层数据库时,不需要改变SQL查询语句,有着更广泛的通用性。命令式语言,在实际应用中出现的情况很少。

    相关文章

      网友评论

        本文标题:《设计数据密集型应用》第二章(2) 查询语言

        本文链接:https://www.haomeiwen.com/subject/jblbaxtx.html