spark查询的执行过程

对于一个查询任务:首先将查询语句解析成一个逻辑计划,并且返回一个LogicalPlan对象。这个逻辑计划包括了查询涉及的表、列、过滤条件、聚合操作等信息,但并没有考虑实际的执行方式和数据分布等因素。
然后我们将这个逻辑计划强制转换为Optimizer.OptimizedLogicalPlan类型,它是一个中间类型,包含了一些额外的信息,例如输入输出的Schema(即数据结构)、是否需要执行Codegen(即生成代码优化)等。这个中间类型是用于在查询优化器中进行处理的,而不是真正的物理计划。

def execute(plan: TreeType): TreeType = {
    var curPlan = plan
    val queryExecutionMetrics = RuleExecutor.queryExecutionMeter
    val planChangeLogger = new PlanChangeLogger[TreeType]()
    val tracker: Option[QueryPlanningTracker] = QueryPlanningTracker.get
    val beforeMetrics = RuleExecutor.getCurrentMetrics()

    val enableValidation = SQLConf.get.getConf(SQLConf.PLAN_CHANGE_VALIDATION)
    // Validate the initial input.
    if (Utils.isTesting || enableValidation) {
      validatePlanChanges(plan, plan) match {
        case Some(msg) =>
          val ruleExecutorName = this.getClass.getName.stripSuffix("$")
          throw new SparkException(
            errorClass = "PLAN_VALIDATION_FAILED_RULE_EXECUTOR",
            messageParameters = Map("ruleExecutor" -> ruleExecutorName, "reason" -> msg),
            cause = null)
        case _ =>
      }
    }

    batches.foreach { batch =>
      val batchStartPlan = curPlan
      var iteration = 1
      var lastPlan = curPlan
      var continue = true

      // Run until fix point (or the max number of iterations as specified in the strategy.
      while (continue) {
        curPlan = batch.rules.foldLeft(curPlan) {
          case (plan, rule) =>
            val startTime = System.nanoTime()
            val result = rule(plan)
            val runTime = System.nanoTime() - startTime
            val effective = !result.fastEquals(plan)

            if (effective) {
              queryExecutionMetrics.incNumEffectiveExecution(rule.ruleName)
              queryExecutionMetrics.incTimeEffectiveExecutionBy(rule.ruleName, runTime)
              planChangeLogger.logRule(rule.ruleName, plan, result)
              // Run the plan changes validation after each rule.
              if (Utils.isTesting || enableValidation) {
                validatePlanChanges(plan, result) match {
                  case Some(msg) =>
                    throw new SparkException(
                      errorClass = "PLAN_VALIDATION_FAILED_RULE_IN_BATCH",
                      messageParameters = Map(
                        "rule" -> rule.ruleName,
                        "batch" -> batch.name,
                        "reason" -> msg),
                      cause = null)
                  case _ =>
                }
              }
            }
            queryExecutionMetrics.incExecutionTimeBy(rule.ruleName, runTime)
            queryExecutionMetrics.incNumExecution(rule.ruleName)

            // Record timing information using QueryPlanningTracker
            tracker.foreach(_.recordRuleInvocation(rule.ruleName, runTime, effective))

            result
        }
        iteration += 1
        if (iteration > batch.strategy.maxIterations) {
          // Only log if this is a rule that is supposed to run more than once.
          if (iteration != 2) {
            val endingMsg = if (batch.strategy.maxIterationsSetting == null) {
              "."
            } else {
              s", please set '${batch.strategy.maxIterationsSetting}' to a larger value."
            }
            val message = s"Max iterations (${iteration - 1}) reached for batch ${batch.name}" +
              s"$endingMsg"
            if (Utils.isTesting || batch.strategy.errorOnExceed) {
              throw new RuntimeException(message)
            } else {
              logWarning(message)
            }
          }
          // Check idempotence for Once batches.
          if (batch.strategy == Once &&
            Utils.isTesting && !excludedOnceBatches.contains(batch.name)) {
            checkBatchIdempotence(batch, curPlan)
          }
          continue = false
        }

        if (curPlan.fastEquals(lastPlan)) {
          logTrace(
            s"Fixed point reached for batch ${batch.name} after ${iteration - 1} iterations.")
          continue = false
        }
        lastPlan = curPlan
      }

      planChangeLogger.logBatch(batch.name, batchStartPlan, curPlan)
    }
    planChangeLogger.logMetrics(RuleExecutor.getCurrentMetrics() - beforeMetrics)

    curPlan
  }

spark.sessionState.optimizer.execute 函数的输入参数是一个经过优化后的逻辑计划,输入类型是 Optimizer.OptimizedLogicalPlan。这个计划包含了SQL查询语句的逻辑结构和一些优化信息,例如可以使用的索引、以及查询执行的方式等等。

函数的返回结果是一个物理计划 SparkPlan。这个物理计划是在逻辑计划的基础上生成的,它包括了具体的执行细节,例如如何进行数据读取、如何进行数据分区,如何进行数据的过滤和排序等等。同样,这个物理计划也会考虑尽可能多的查询优化技术,以提高查询的执行效率。

需要注意的是,spark.sessionState.optimizer.execute 函数只处理查询的优化和转换,而不会执行查询本身。如果需要真正执行查询,我们需要将这个物理计划传递给查询引擎进行实际的查询操作。通常使用DataFrame或Dataset来封装查询请求后,调用show、collect等方法即可执行查询并打印结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spark执行流程可以简单概括为以下几个步骤: 1. 创建SparkContext:Spark应用程序首先会创建一个SparkContext对象,它是与集群交互的主要入口点,并负责与集群管理器进行通信。 2. 定义并加载数据:在Spark应用程序中,您需要定义数据的来源,例如从文件系统、Hive表或其他外部数据源加载数据。Spark提供了各种API和工具来处理各种数据格式。 3. 转换操作:一旦数据加载完成,您可以使用Spark提供的转换操作来对数据进行处理和转换。这些转换操作包括过滤、映射、聚合等,可以根据您的需求对数据进行修改。 4. 缓存数据(可选):如果需要多次访问同一份数据,可以选择将其缓存到内存中,以加快后续的操作速度。缓存可以提高性能,但也需要考虑内存消耗。 5. 执行操作:一旦定义了转换操作,Spark会根据依赖关系图构建执行计划。Spark执行是惰性的,只有在遇到动作操作时才会真正执行。动作操作包括对数据进行计数、收集、保存等。 6. 优化执行计划:在执行计划构建完成后,Spark会对执行计划进行优化,以提高查询性能。它会根据数据的特性和集群资源进行优化,并尽量减少数据的移动和网络传输。 7. 提交任务:一旦执行计划优化完成,Spark会将任务提交给集群管理器进行执行。集群管理器负责将任务分配到集群中的不同节点上,并协调任务的执行。 8. 监控和调优:在任务执行期间,您可以监控任务的进度和性能。通过监控工具和日志,您可以了解任务的执行情况,并进行调优以提高性能。 9. 获取结果:一旦任务执行完成,您可以获取执行结果,并根据需要进行后续的处理和分析。 这是一个简单的描述,实际上Spark执行流程还涉及到许多细节和优化策略,但以上步骤可以帮助您理解Spark的基本执行流程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值