精华内容
下载资源
问答
  • 链接的网站快照、外链、收录、反链接查询.rar
  • SEO反链接查询工具link survey,很好的帮你查找竞争对手的外链情况,从而进行自己网站的外链操作。
  • 该软件需要.NET2.0的支持,使用了多线程开发,速度很快,包含google,sogou,alexa,china排名查询,可以查询目前几大搜索引擎的收录和反链接的情况,是你了解网站情况的好帮手
  • 反向链接查询分析工具,查询网站链详细情况,SEO分析必备。
  • 非常实用的一个SEO工具 可以查询网站的外链情况 包括锚文本链接,使用哪些关键字,哪些网页包含网站域名,有那些网站带有指向网站的超链等 对分析网站,强化SEO效果有很大帮助
  • 对于SEO初学者而言,经常容易混淆反向链接与外部链接,大家并不清楚二者之间的区别,这对于SEO优化而言,却有着完全不同的概念,比如:增加链与增加外链,严格意义上讲,这是两码事。 那么,反向链接...

    对于SEO初学者而言,经常容易混淆反向链接与外部链接,大家并不清楚二者之间的区别,这对于SEO优化而言,却有着完全不同的概念,比如:增加反链与增加外链,严格意义上讲,这是两码事。  

    那么,反向链接与外链的区别有哪些?  

    简单举例,比如:X与Y这两个页面,如果SEO人员在Y的页面上,利用超链接指向了X页面,那么我们可以明确的指出Y页面的URL,就是X页面的 反向链接 。  

    这里面值得关注的一件事情是:  

    我们并没有严格要求,X页面与Y页面,不能来自于同一个主域,言外之意,我们可以这么理解:  

    ①X页面与Y页面,来自不同主域的反向链接,我们可以理解为 外部链接 。  

    ②X页面与Y页面,来自于同一个主域的反向链接,我们可以称之为内链。  

    所以,我们可以轻易的得出概念,反向链接它包括:外部链接+内链,与外链有着明显的区别,在制定某些SEO策略的时候,如果说你需要适当增加反向链接,那么,你增加外链的同时,也需要增加内链。  

    那么,反向链接查询的方法有哪些?  

    1、利用站长工具查询  

    国内常见的可查询反向链接的工具,大家主要可以利用:爱站的“网站反链”查询工具。  

    它的主要功能包括:  

    ①网站首页反链查询  

    ②网站内页反链查询  

    从目前来看,这个反链查询工具,相对精准,基本上可以识别大部分网站的反向链接,但这个通常只是识别外部链接,对于站内链接,并不能很好的识别。  

    2、利用谷歌站长工具  

    虽然,谷歌早已推出中国,近期又有传闻意预回归,但谷歌一直没有放弃对中文内容的检索,其中对于谷歌SEO而言,它在官方站长工具中,提供了一个非常便利的工具。  

    只要你验证通过谷歌站长工具,它就可以清晰的识别出你的网站内部链接,以及外部链接。  

    3、利用命令domain查询  

    对于domain这个命令而言,同样查询的只是反向链接中的外部链接,但在大部分SEO诊断中,SEO人员有的时候,只是优先考量外链的组成。  

    而利用这个命令,只能是进行一个简单粗略的参考。  

    4、国内付费SEO管理工具  

    目前,国内一些专业的SEO机构,它提供付费的管理软件,可以有效的识别:反向链接,通常是通过自己编译的爬虫抓取全网的中文站点。  

    开发这类软件,维护成本相对较高,并且并不怎么公开出售,只有少数优质的SEO机构之间自用。  

    总结:反向链接是衡量一个站点,站内与站外链接资源的重要参考指标,对SEO优化,具有积极的参考价值。  

    来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31519093/viewspace-2212958/,如需转载,请注明出处,否则将追究法律责任。

    转载于:http://blog.itpub.net/31519093/viewspace-2212958/

    展开全文
  • 本文简单介绍了PG查询逻辑优化中的子查询链接(subLink),主要内容包括子链接的基本概念,介绍了主函数以及使用gdb跟踪分析了上拉函数的部分处理逻辑。 上拉子链接的目的是为了把子链接改写为半连接或...

    本文简单介绍了PG查询逻辑优化中的子查询链接(subLink),主要内容包括子链接的基本概念,介绍了主函数以及使用gdb跟踪分析了上拉函数的部分处理逻辑。
    上拉子链接的目的是为了把子链接改写为半连接或反半连接的方式提升性能。

    一、子链接简介

    按官方文档的介绍,子链接Sublink代表的是出现在表达式(可能会出现组合运算符)中的子查询,子查询的类型包括:
    EXISTS_SUBLINK
    语法:EXISTS(SELECT ...)

    select * 
    from t_dwxx a
    where exists (select b.dwbh from t_grxx b where a.dwbh = b.dwbh);
    

    ALL_SUBLINK
    语法:(lefthand) op ALL (SELECT ...)

    select * 
    from t_dwxx a
    where dwbh > all (select b.dwbh from t_grxx b);
    

    ANY_SUBLINK
    语法:(lefthand) op ANY (SELECT ...)

    select * 
    from t_dwxx a
    where dwbh = any (select b.dwbh from t_grxx b);
    

    ROWCOMPARE_SUBLINK
    语法:(lefthand) op (SELECT ...)

    select * 
    from t_dwxx a
    where dwbh > (select max(b.dwbh) from t_grxx b);
    

    EXPR_SUBLINK
    语法:(SELECT with single targetlist item ...)

    select *,(select max(dwbh) from t_grxx) 
    from t_dwxx a;
    

    MULTIEXPR_SUBLINK
    语法:(SELECT with multiple targetlist items ...)

    ARRAY_SUBLINK
    语法:ARRAY(SELECT with single targetlist item ...)

    CTE_SUBLINK
    语法:
    WITH query (never actually part of an expression)

    官方说明:

    /*
     * SubLink
     *
     * A SubLink represents a subselect appearing in an expression, and in some
     * cases also the combining operator(s) just above it.  The subLinkType
     * indicates the form of the expression represented:
     *  EXISTS_SUBLINK    EXISTS(SELECT ...)
     *  ALL_SUBLINK     (lefthand) op ALL (SELECT ...)
     *  ANY_SUBLINK     (lefthand) op ANY (SELECT ...)
     *  ROWCOMPARE_SUBLINK  (lefthand) op (SELECT ...)
     *  EXPR_SUBLINK    (SELECT with single targetlist item ...)
     *  MULTIEXPR_SUBLINK (SELECT with multiple targetlist items ...)
     *  ARRAY_SUBLINK   ARRAY(SELECT with single targetlist item ...)
     *  CTE_SUBLINK     WITH query (never actually part of an expression)
     * For ALL, ANY, and ROWCOMPARE, the lefthand is a list of expressions of the
     * same length as the subselect's targetlist.  ROWCOMPARE will *always* have
     * a list with more than one entry; if the subselect has just one target
     * then the parser will create an EXPR_SUBLINK instead (and any operator
     * above the subselect will be represented separately).
     * ROWCOMPARE, EXPR, and MULTIEXPR require the subselect to deliver at most
     * one row (if it returns no rows, the result is NULL).
     * ALL, ANY, and ROWCOMPARE require the combining operators to deliver boolean
     * results.  ALL and ANY combine the per-row results using AND and OR
     * semantics respectively.
     * ARRAY requires just one target column, and creates an array of the target
     * column's type using any number of rows resulting from the subselect.
     * 
     * 子链接属于Expr Node,但并不意味着子链接是可以执行的.子链接必须在计划期间通过子计划节点在表达式树中替换
     * SubLink is classed as an Expr node, but it is not actually executable;
     * it must be replaced in the expression tree by a SubPlan node during
     * planning.
     *
     * NOTE: in the raw output of gram.y, testexpr contains just the raw form
     * of the lefthand expression (if any), and operName is the String name of
     * the combining operator.  Also, subselect is a raw parsetree.  During parse
     * analysis, the parser transforms testexpr into a complete boolean expression
     * that compares the lefthand value(s) to PARAM_SUBLINK nodes representing the
     * output columns of the subselect.  And subselect is transformed to a Query.
     * This is the representation seen in saved rules and in the rewriter.
     *
     * In EXISTS, EXPR, MULTIEXPR, and ARRAY SubLinks, testexpr and operName
     * are unused and are always null.
     *
     * subLinkId is currently used only for MULTIEXPR SubLinks, and is zero in
     * other SubLinks.  This number identifies different multiple-assignment
     * subqueries within an UPDATE statement's SET list.  It is unique only
     * within a particular targetlist.  The output column(s) of the MULTIEXPR
     * are referenced by PARAM_MULTIEXPR Params appearing elsewhere in the tlist.
     *
     * The CTE_SUBLINK case never occurs in actual SubLink nodes, but it is used
     * in SubPlans generated for WITH subqueries.
     */
    typedef enum SubLinkType
    {
      EXISTS_SUBLINK,
      ALL_SUBLINK,
      ANY_SUBLINK,
      ROWCOMPARE_SUBLINK,
      EXPR_SUBLINK,
      MULTIEXPR_SUBLINK,
      ARRAY_SUBLINK,
      CTE_SUBLINK         /* for SubPlans only */
    } SubLinkType;
    
    
    typedef struct SubLink
    {
      Expr    xpr;
      SubLinkType subLinkType;  /* see above */
      int     subLinkId;    /* ID (1..n); 0 if not MULTIEXPR */
      Node     *testexpr;   /* outer-query test for ALL/ANY/ROWCOMPARE */
      List     *operName;   /* originally specified operator name */
      Node     *subselect;    /* subselect as Query* or raw parsetree */
      int     location;   /* token location, or -1 if unknown */
    } SubLink;
    
    

    二、源码解读

    standard_planner函数

    /*****************************************************************************
      *
      *     Query optimizer entry point
      *
      * To support loadable plugins that monitor or modify planner behavior,
      * we provide a hook variable that lets a plugin get control before and
      * after the standard planning process.  The plugin would normally call
      * standard_planner().
      *
      * Note to plugin authors: standard_planner() scribbles on its Query input,
      * so you'd better copy that data structure if you want to plan more than once.
      *
      *****************************************************************************/
     PlannedStmt *
     planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
     {
         PlannedStmt *result;
     
         if (planner_hook)
             result = (*planner_hook) (parse, cursorOptions, boundParams); //钩子函数,可以实现定制化开发
         else
             result = standard_planner(parse, cursorOptions, boundParams);//PG的标准实现
         return result;
     }
     
     /*
     输入参数:
        parse-查询树
        cursorOptions-游标处理选项,见本节中的数据结构
        boundParams-绑定变量?
     输出参数:
     */
     PlannedStmt *
     standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
     {
         PlannedStmt *result;//最终结果
         PlannerGlobal *glob;//全局优化信息
         double      tuple_fraction;//优化过程中元组的采样率
         PlannerInfo *root;//执行计划的根节点
         RelOptInfo *final_rel;//优化后的Relation信息
         Path       *best_path;//最优路径
         Plan       *top_plan;//顶层计划
         ListCell   *lp,//临时变量
                    *lr;
     
         /*
          * Set up global state for this planner invocation.  This data is needed
          * across all levels of sub-Query that might exist in the given command,
          * so we keep it in a separate struct that's linked to by each per-Query
          * PlannerInfo.
          */
         //初始化全局优化信息 
         glob = makeNode(PlannerGlobal);
     
         glob->boundParams = boundParams;
         glob->subplans = NIL;
         glob->subroots = NIL;
         glob->rewindPlanIDs = NULL;
         glob->finalrtable = NIL;
         glob->finalrowmarks = NIL;
         glob->resultRelations = NIL;
         glob->nonleafResultRelations = NIL;
         glob->rootResultRelations = NIL;
         glob->relationOids = NIL;
         glob->invalItems = NIL;
         glob->paramExecTypes = NIL;
         glob->lastPHId = 0;
         glob->lastRowMarkId = 0;
         glob->lastPlanNodeId = 0;
         glob->transientPlan = false;
         glob->dependsOnRole = false;
     
         /*
          * Assess whether it's feasible to use parallel mode for this query. We
          * can't do this in a standalone backend, or if the command will try to
          * modify any data, or if this is a cursor operation, or if GUCs are set
          * to values that don't permit parallelism, or if parallel-unsafe
          * functions are present in the query tree.
          *
          * (Note that we do allow CREATE TABLE AS, SELECT INTO, and CREATE
          * MATERIALIZED VIEW to use parallel plans, but this is safe only because
          * the command is writing into a completely new table which workers won't
          * be able to see.  If the workers could see the table, the fact that
          * group locking would cause them to ignore the leader's heavyweight
          * relation extension lock and GIN page locks would make this unsafe.
          * We'll have to fix that somehow if we want to allow parallel inserts in
          * general; updates and deletes have additional problems especially around
          * combo CIDs.)
          *
          * For now, we don't try to use parallel mode if we're running inside a
          * parallel worker.  We might eventually be able to relax this
          * restriction, but for now it seems best not to have parallel workers
          * trying to create their own parallel workers.
          *
          * We can't use parallelism in serializable mode because the predicate
          * locking code is not parallel-aware.  It's not catastrophic if someone
          * tries to run a parallel plan in serializable mode; it just won't get
          * any workers and will run serially.  But it seems like a good heuristic
          * to assume that the same serialization level will be in effect at plan
          * time and execution time, so don't generate a parallel plan if we're in
          * serializable mode.
          */
         //判断是否可以使用并行模式
         //并行是很大的一个话题,有待以后再谈 
         if ((cursorOptions & CURSOR_OPT_PARALLEL_OK) != 0 &&
             IsUnderPostmaster &&
             parse->commandType == CMD_SELECT &&
             !parse->hasModifyingCTE &&
             max_parallel_workers_per_gather > 0 &&
             !IsParallelWorker() &&
             !IsolationIsSerializable())
         {
             /* all the cheap tests pass, so scan the query tree */
             glob->maxParallelHazard = max_parallel_hazard(parse);
             glob->parallelModeOK = (glob->maxParallelHazard != PROPARALLEL_UNSAFE);
         }
         else
         {
             /* skip the query tree scan, just assume it's unsafe */
             glob->maxParallelHazard = PROPARALLEL_UNSAFE;
             glob->parallelModeOK = false;
         }
     
         /*
          * glob->parallelModeNeeded is normally set to false here and changed to
          * true during plan creation if a Gather or Gather Merge plan is actually
          * created (cf. create_gather_plan, create_gather_merge_plan).
          *
          * However, if force_parallel_mode = on or force_parallel_mode = regress,
          * then we impose parallel mode whenever it's safe to do so, even if the
          * final plan doesn't use parallelism.  It's not safe to do so if the
          * query contains anything parallel-unsafe; parallelModeOK will be false
          * in that case.  Note that parallelModeOK can't change after this point.
          * Otherwise, everything in the query is either parallel-safe or
          * parallel-restricted, and in either case it should be OK to impose
          * parallel-mode restrictions.  If that ends up breaking something, then
          * either some function the user included in the query is incorrectly
          * labelled as parallel-safe or parallel-restricted when in reality it's
          * parallel-unsafe, or else the query planner itself has a bug.
          */
         glob->parallelModeNeeded = glob->parallelModeOK &&
             (force_parallel_mode != FORCE_PARALLEL_OFF);
     
         /* Determine what fraction of the plan is likely to be scanned */
         if (cursorOptions & CURSOR_OPT_FAST_PLAN)//fast-start plan?
         {
             /*
              * We have no real idea how many tuples the user will ultimately FETCH
              * from a cursor, but it is often the case that he doesn't want 'em
              * all, or would prefer a fast-start plan anyway so that he can
              * process some of the tuples sooner.  Use a GUC parameter to decide
              * what fraction to optimize for.
              */
             tuple_fraction = cursor_tuple_fraction;
     
             /*
              * We document cursor_tuple_fraction as simply being a fraction, which
              * means the edge cases 0 and 1 have to be treated specially here.  We
              * convert 1 to 0 ("all the tuples") and 0 to a very small fraction.
              */
             if (tuple_fraction >= 1.0)
                 tuple_fraction = 0.0;
             else if (tuple_fraction <= 0.0)
                 tuple_fraction = 1e-10;
         }
         else
         {
             /* Default assumption is we need all the tuples */
             tuple_fraction = 0.0;
         }
         //以上:set up for recursive handling of subqueries,为子查询配置处理器(递归方式)
         /* primary planning entry point (may recurse for subqueries) */
         root = subquery_planner(glob, parse, NULL,
                                 false, tuple_fraction);//进入子查询优化器
     
         /* Select best Path and turn it into a Plan */
         final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);//获得最上层的优化后的Relation
         best_path = get_cheapest_fractional_path(final_rel, tuple_fraction);//获得最佳路径
     
         top_plan = create_plan(root, best_path);//创建计划
     
         /*
          * If creating a plan for a scrollable cursor, make sure it can run
          * backwards on demand.  Add a Material node at the top at need.
          */
         if (cursorOptions & CURSOR_OPT_SCROLL)
         {
             if (!ExecSupportsBackwardScan(top_plan))
                 top_plan = materialize_finished_plan(top_plan);//如果是Scroll游标,在前台执行,那么物化之(数据不能长期占用内存,但又要满足Scroll的要求,需要物化至磁盘中)
         }
     
         /*
          * Optionally add a Gather node for testing purposes, provided this is
          * actually a safe thing to do.
          */
         if (force_parallel_mode != FORCE_PARALLEL_OFF && top_plan->parallel_safe)//并行执行,添加Gather节点
         {
             Gather     *gather = makeNode(Gather);
     
             /*
              * If there are any initPlans attached to the formerly-top plan node,
              * move them up to the Gather node; same as we do for Material node in
              * materialize_finished_plan.
              */
             gather->plan.initPlan = top_plan->initPlan;
             top_plan->initPlan = NIL;
     
             gather->plan.targetlist = top_plan->targetlist;
             gather->plan.qual = NIL;
             gather->plan.lefttree = top_plan;
             gather->plan.righttree = NULL;
             gather->num_workers = 1;
             gather->single_copy = true;
             gather->invisible = (force_parallel_mode == FORCE_PARALLEL_REGRESS);
     
             /*
              * Since this Gather has no parallel-aware descendants to signal to,
              * we don't need a rescan Param.
              */
             gather->rescan_param = -1;
     
             /*
              * Ideally we'd use cost_gather here, but setting up dummy path data
              * to satisfy it doesn't seem much cleaner than knowing what it does.
              */
             gather->plan.startup_cost = top_plan->startup_cost +
                 parallel_setup_cost;
             gather->plan.total_cost = top_plan->total_cost +
                 parallel_setup_cost + parallel_tuple_cost * top_plan->plan_rows;
             gather->plan.plan_rows = top_plan->plan_rows;
             gather->plan.plan_width = top_plan->plan_width;
             gather->plan.parallel_aware = false;
             gather->plan.parallel_safe = false;
     
             /* use parallel mode for parallel plans. */
             root->glob->parallelModeNeeded = true;
     
             top_plan = &gather->plan;
         }
     
         /*
          * If any Params were generated, run through the plan tree and compute
          * each plan node's extParam/allParam sets.  Ideally we'd merge this into
          * set_plan_references' tree traversal, but for now it has to be separate
          * because we need to visit subplans before not after main plan.
          */
         if (glob->paramExecTypes != NIL)
         {
             Assert(list_length(glob->subplans) == list_length(glob->subroots));
             forboth(lp, glob->subplans, lr, glob->subroots)
             {
                 Plan       *subplan = (Plan *) lfirst(lp);
                 PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
     
                 SS_finalize_plan(subroot, subplan);
             }
             SS_finalize_plan(root, top_plan);
         }
     
         /* final cleanup of the plan */
         Assert(glob->finalrtable == NIL);
         Assert(glob->finalrowmarks == NIL);
         Assert(glob->resultRelations == NIL);
         Assert(glob->nonleafResultRelations == NIL);
         Assert(glob->rootResultRelations == NIL);
         top_plan = set_plan_references(root, top_plan);
         /* ... and the subplans (both regular subplans and initplans) */
         Assert(list_length(glob->subplans) == list_length(glob->subroots));
         forboth(lp, glob->subplans, lr, glob->subroots)
         {
             Plan       *subplan = (Plan *) lfirst(lp);
             PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
     
             lfirst(lp) = set_plan_references(subroot, subplan);
         }
     
         /* build the PlannedStmt result */
         result = makeNode(PlannedStmt);
     
         result->commandType = parse->commandType;
         result->queryId = parse->queryId;
         result->hasReturning = (parse->returningList != NIL);
         result->hasModifyingCTE = parse->hasModifyingCTE;
         result->canSetTag = parse->canSetTag;
         result->transientPlan = glob->transientPlan;
         result->dependsOnRole = glob->dependsOnRole;
         result->parallelModeNeeded = glob->parallelModeNeeded;
         result->planTree = top_plan;
         result->rtable = glob->finalrtable;
         result->resultRelations = glob->resultRelations;
         result->nonleafResultRelations = glob->nonleafResultRelations;
         result->rootResultRelations = glob->rootResultRelations;
         result->subplans = glob->subplans;
         result->rewindPlanIDs = glob->rewindPlanIDs;
         result->rowMarks = glob->finalrowmarks;
         result->relationOids = glob->relationOids;
         result->invalItems = glob->invalItems;
         result->paramExecTypes = glob->paramExecTypes;
         /* utilityStmt should be null, but we might as well copy it */
         result->utilityStmt = parse->utilityStmt;
         result->stmt_location = parse->stmt_location;
         result->stmt_len = parse->stmt_len;
     
         result->jitFlags = PGJIT_NONE;
         if (jit_enabled && jit_above_cost >= 0 &&
             top_plan->total_cost > jit_above_cost)
         {
             result->jitFlags |= PGJIT_PERFORM;
     
             /*
              * Decide how much effort should be put into generating better code.
              */
             if (jit_optimize_above_cost >= 0 &&
                 top_plan->total_cost > jit_optimize_above_cost)
                 result->jitFlags |= PGJIT_OPT3;
             if (jit_inline_above_cost >= 0 &&
                 top_plan->total_cost > jit_inline_above_cost)
                 result->jitFlags |= PGJIT_INLINE;
     
             /*
              * Decide which operations should be JITed.
              */
             if (jit_expressions)
                 result->jitFlags |= PGJIT_EXPR;
             if (jit_tuple_deforming)
                 result->jitFlags |= PGJIT_DEFORM;
         }
     
         return result;
     }
    

    subquery_planner

     /*--------------------
      * subquery_planner
      *    Invokes the planner on a subquery.  We recurse to here for each
      *    sub-SELECT found in the query tree.
      *
      * glob is the global state for the current planner run.
      * parse is the querytree produced by the parser & rewriter.
      * parent_root is the immediate parent Query's info (NULL at the top level).
      * hasRecursion is true if this is a recursive WITH query.
      * tuple_fraction is the fraction of tuples we expect will be retrieved.
      * tuple_fraction is interpreted as explained for grouping_planner, below.
      *
      * Basically, this routine does the stuff that should only be done once
      * per Query object.  It then calls grouping_planner.  At one time,
      * grouping_planner could be invoked recursively on the same Query object;
      * that's not currently true, but we keep the separation between the two
      * routines anyway, in case we need it again someday.
      *
      * subquery_planner will be called recursively to handle sub-Query nodes
      * found within the query's expressions and rangetable.
      *
      * Returns the PlannerInfo struct ("root") that contains all data generated
      * while planning the subquery.  In particular, the Path(s) attached to
      * the (UPPERREL_FINAL, NULL) upperrel represent our conclusions about the
      * cheapest way(s) to implement the query.  The top level will select the
      * best Path and pass it through createplan.c to produce a finished Plan.
      *--------------------
      */
    /*
    输入:
        glob-PlannerGlobal
        parse-Query结构体指针
        parent_root-父PlannerInfo Root节点
        hasRecursion-是否递归?
        tuple_fraction-扫描Tuple比例
    输出:
        PlannerInfo指针
    */
     PlannerInfo *
     subquery_planner(PlannerGlobal *glob, Query *parse,
                      PlannerInfo *parent_root,
                      bool hasRecursion, double tuple_fraction)
     {
         PlannerInfo *root;//返回值
         List       *newWithCheckOptions;//
         List       *newHaving;//Having子句
         bool        hasOuterJoins;//是否存在Outer Join?
         RelOptInfo *final_rel;//
         ListCell   *l;//临时变量
     
         /* Create a PlannerInfo data structure for this subquery */
         root = makeNode(PlannerInfo);//构造返回值
         root->parse = parse;
         root->glob = glob;
         root->query_level = parent_root ? parent_root->query_level + 1 : 1;
         root->parent_root = parent_root;
         root->plan_params = NIL;
         root->outer_params = NULL;
         root->planner_cxt = CurrentMemoryContext;
         root->init_plans = NIL;
         root->cte_plan_ids = NIL;
         root->multiexpr_params = NIL;
         root->eq_classes = NIL;
         root->append_rel_list = NIL;
         root->rowMarks = NIL;
         memset(root->upper_rels, 0, sizeof(root->upper_rels));
         memset(root->upper_targets, 0, sizeof(root->upper_targets));
         root->processed_tlist = NIL;
         root->grouping_map = NULL;
         root->minmax_aggs = NIL;
         root->qual_security_level = 0;
         root->inhTargetKind = INHKIND_NONE;
         root->hasRecursion = hasRecursion;
         if (hasRecursion)
             root->wt_param_id = SS_assign_special_param(root);
         else
             root->wt_param_id = -1;
         root->non_recursive_path = NULL;
         root->partColsUpdated = false;
     
         /*
          * If there is a WITH list, process each WITH query and build an initplan
          * SubPlan structure for it.
          */
         if (parse->cteList)
             SS_process_ctes(root);//处理With 语句
     
         /*
          * Look for ANY and EXISTS SubLinks in WHERE and JOIN/ON clauses, and try
          * to transform them into joins.  Note that this step does not descend
          * into subqueries; if we pull up any subqueries below, their SubLinks are
          * processed just before pulling them up.
          */
         if (parse->hasSubLinks)
             pull_up_sublinks(root); //上拉子链接
     
         //其他内容...
    
         return root;
     }
     
    

    pull_up_sublinks

    下一小节介绍
    

    三、基础信息

    数据结构/宏定义
    1、cursorOptions

     /* ----------------------
      *      Declare Cursor Statement
      *
      * The "query" field is initially a raw parse tree, and is converted to a
      * Query node during parse analysis.  Note that rewriting and planning
      * of the query are always postponed until execution.
      * ----------------------
      */
     #define CURSOR_OPT_BINARY       0x0001  /* BINARY */
     #define CURSOR_OPT_SCROLL       0x0002  /* SCROLL explicitly given */
     #define CURSOR_OPT_NO_SCROLL    0x0004  /* NO SCROLL explicitly given */
     #define CURSOR_OPT_INSENSITIVE  0x0008  /* INSENSITIVE */
     #define CURSOR_OPT_HOLD         0x0010  /* WITH HOLD */
     /* these planner-control flags do not correspond to any SQL grammar: */
     #define CURSOR_OPT_FAST_PLAN    0x0020  /* prefer fast-start plan */
     #define CURSOR_OPT_GENERIC_PLAN 0x0040  /* force use of generic plan */
     #define CURSOR_OPT_CUSTOM_PLAN  0x0080  /* force use of custom 
     #define CURSOR_OPT_PARALLEL_OK  0x0100  /* parallel mode OK */
    

    2、Relids

     /*
      * Relids
      *      Set of relation identifiers (indexes into the rangetable).
      */
     typedef Bitmapset *Relids;
     /* The unit size can be adjusted by changing these three declarations: */
     #define BITS_PER_BITMAPWORD 32
     typedef uint32 bitmapword;      /* must be an unsigned type */
     typedef int32 signedbitmapword; /* must be the matching signed type */
     
     typedef struct Bitmapset
     {
         int         nwords;         /* number of words in array */
         bitmapword  words[FLEXIBLE_ARRAY_MEMBER];   /* really [nwords] */
     } Bitmapset; 
    

    四、跟踪分析

    测试脚本:

    testdb=# explain select * 
    from t_dwxx a
    where dwbh > all (select b.dwbh from t_grxx b);
                                    QUERY PLAN                                
    --------------------------------------------------------------------------
     Seq Scan on t_dwxx a  (cost=0.00..1498.00 rows=80 width=474)
       Filter: (SubPlan 1)
       SubPlan 1
         ->  Materialize  (cost=0.00..17.35 rows=490 width=38)
               ->  Seq Scan on t_grxx b  (cost=0.00..14.90 rows=490 width=38)
    (5 rows)
    

    启动gdb跟踪:

    (gdb) b pull_up_sublinks
    Breakpoint 1 at 0x77cbc6: file prepjointree.c, line 157.
    (gdb) c
    Continuing.
    
    Breakpoint 1, pull_up_sublinks (root=0x126fd48) at prepjointree.c:157
    157                          (Node *) root->parse->jointree,
    (gdb) 
    #查看输入参数
    (gdb) p *root
    $1 = {type = T_PlannerInfo, parse = 0x11b43d8, glob = 0x11b4e00, query_level = 1, parent_root = 0x0, plan_params = 0x0, 
      outer_params = 0x0, simple_rel_array = 0x0, simple_rel_array_size = 0, simple_rte_array = 0x0, all_baserels = 0x0, 
      nullable_baserels = 0x0, join_rel_list = 0x0, join_rel_hash = 0x0, join_rel_level = 0x0, join_cur_level = 0, 
      init_plans = 0x0, cte_plan_ids = 0x0, multiexpr_params = 0x0, eq_classes = 0x0, canon_pathkeys = 0x0, 
      left_join_clauses = 0x0, right_join_clauses = 0x0, full_join_clauses = 0x0, join_info_list = 0x0, append_rel_list = 0x0, 
      rowMarks = 0x0, placeholder_list = 0x0, fkey_list = 0x0, query_pathkeys = 0x0, group_pathkeys = 0x0, 
      window_pathkeys = 0x0, distinct_pathkeys = 0x0, sort_pathkeys = 0x0, part_schemes = 0x0, initial_rels = 0x0, 
      upper_rels = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, upper_targets = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
      processed_tlist = 0x0, grouping_map = 0x0, minmax_aggs = 0x0, planner_cxt = 0x11b2e90, total_table_pages = 0, 
      tuple_fraction = 0, limit_tuples = 0, qual_security_level = 0, inhTargetKind = INHKIND_NONE, hasJoinRTEs = false, 
      hasLateralRTEs = false, hasDeletedRTEs = false, hasHavingQual = false, hasPseudoConstantQuals = false, 
      hasRecursion = false, wt_param_id = -1, non_recursive_path = 0x0, curOuterRels = 0x0, curOuterParams = 0x0, 
      join_search_private = 0x0, partColsUpdated = false}
    #jointree的类型为FromExpr  
    (gdb) p *root->parse->jointree
    $3 = {type = T_FromExpr, fromlist = 0x11b4870, quals = 0x11b40e8}
    (gdb) n
    156   jtnode = pull_up_sublinks_jointree_recurse(root,
    #进入pull_up_sublinks_jointree_recurse函数
    (gdb) step
    pull_up_sublinks_jointree_recurse (root=0x126fd48, jtnode=0x1282ea0, relids=0x7ffe830ab9b0) at prepjointree.c:180
    180   if (jtnode == NULL)
    #查看参数
    #1.root与pull_up_sublinks函数的输入一致
    #2.jtnode类型为FromExpr
    #3.relids
    (gdb) p *jtnode
    $7 = {type = T_FromExpr}
    (gdb) p *(FromExpr *)jtnode
    $8 = {type = T_FromExpr, fromlist = 0x11b4870, quals = 0x11b40e8}
    #FromExpr->fromlist中的的元素类型为RangeTblRef
    (gdb) p *((FromExpr *)jtnode)->fromlist
    $9 = {type = T_List, length = 1, head = 0x11b4850, tail = 0x11b4850}
    (gdb) p *(Node *)((FromExpr *)jtnode)->fromlist->head->data.ptr_value
    $10 = {type = T_RangeTblRef}
    ...
    #进入FromExpr分支
    191   else if (IsA(jtnode, FromExpr))
    ...
    201     foreach(l, f->fromlist)
    (gdb) 
    207                              lfirst(l),
    (gdb) p *l
    $11 = {data = {ptr_value = 0x11b4838, int_value = 18565176, oid_value = 18565176}, next = 0x0}
    (gdb) p *(RangeTblRef *)l->data.ptr_value
    $13 = {type = T_RangeTblRef, rtindex = 1}
    #递归调用pull_up_sublinks_jointree_recurse
    (gdb) n
    206       newchild = pull_up_sublinks_jointree_recurse(root,
    (gdb) step
    pull_up_sublinks_jointree_recurse (root=0x126fd48, jtnode=0x11b4838, relids=0x7ffe830ab940) at prepjointree.c:180
    180   if (jtnode == NULL)
    #输入参数
    #1.root与pull_up_sublinks函数的输入一致
    #2.jtnode类型为RangeTblRef
    #3.relids
    #进入RangeTblRef分支
    (gdb) n
    184   else if (IsA(jtnode, RangeTblRef))
    (gdb) n
    186     int     varno = ((RangeTblRef *) jtnode)->rtindex;
    (gdb) 
    188     *relids = bms_make_singleton(varno);
    (gdb) 
    312   return jtnode;
    (gdb) p *relids
    $16 = (Relids) 0x12704c8
    ...
    (gdb) p *newchild
    $19 = {type = T_RangeTblRef}
    (gdb) n
    210       frelids = bms_join(frelids, childrelids);
    (gdb) p *frelids
    $25 = {nwords = 1, words = 0x12704cc}
    (gdb) p *frelids->words
    $26 = 2
    ...
    #进入pull_up_sublinks_qual_recurse
    (gdb) n
    217     newf->quals = pull_up_sublinks_qual_recurse(root, f->quals,
    (gdb) step
    pull_up_sublinks_qual_recurse (root=0x126fd48, node=0x11b40e8, jtlink1=0x7ffe830ab948, available_rels1=0x12704c8, 
        jtlink2=0x0, available_rels2=0x0) at prepjointree.c:335
    335   if (node == NULL)
    #输入参数
    #1.root与上述无异
    #2.node
    (gdb) p *node
    $35 = {type = T_SubLink}
    (gdb) p *(SubLink *)node
    $36 = {xpr = {type = T_SubLink}, subLinkType = ALL_SUBLINK, subLinkId = 0, testexpr = 0x1282e00, operName = 0x11b3cf8, 
      subselect = 0x1282578, location = 35}
    #3.jtlink1,指针数组
    (gdb) p *(RangeTblRef *)((FromExpr *)jtlink1[0])->fromlist->head->data->ptr_value
    $45 = {type = T_RangeTblRef, rtindex = 1}
    #4.available_rels1,可用的Relids
    (gdb) p *available_rels1
    $47 = {nwords = 1, words = 0x12704cc}
    (gdb) p *available_rels1->words
    $48 = 2
    #5/6,NULL值
    (gdb) n
    337   if (IsA(node, SubLink))
    (gdb) 
    339     SubLink    *sublink = (SubLink *) node;
    (gdb) 
    344     if (sublink->subLinkType == ANY_SUBLINK)
    (gdb) 
    398     else if (sublink->subLinkType == EXISTS_SUBLINK)
    (gdb) p sublink->subLinkType
    $49 = ALL_SUBLINK
    #非ANY/EXISTS链接,退出
    (gdb) n
    453     return node;
    (gdb) 
    #回到pull_up_sublinks_jointree_recurse
    (gdb) 
    pull_up_sublinks_jointree_recurse (root=0x126fd48, jtnode=0x1282ea0, relids=0x7ffe830ab9b0) at prepjointree.c:230
    230     *relids = frelids;
    (gdb) 
    231     jtnode = jtlink;
    (gdb) 
    312   return jtnode;
    #返回的jtnode为RangeTblRef
    (gdb) p *(RangeTblRef *)((FromExpr *)jtnode)->fromlist->head->data.ptr_value
    $55 = {type = T_RangeTblRef, rtindex = 1}
    (gdb) n
    313 }
    (gdb) 
    pull_up_sublinks (root=0x126fd48) at prepjointree.c:164
    164   if (IsA(jtnode, FromExpr))
    (gdb) 
    165     root->parse->jointree = (FromExpr *) jtnode;
    (gdb) p *root->parse->jointree
    $56 = {type = T_FromExpr, fromlist = 0x11b4870, quals = 0x11b40e8}
    (gdb) p *root->parse->jointree->fromlist
    $57 = {type = T_List, length = 1, head = 0x11b4850, tail = 0x11b4850}
    (gdb) n
    168 }
    (gdb) 
    subquery_planner (glob=0x11b4e00, parse=0x11b43d8, parent_root=0x0, hasRecursion=false, tuple_fraction=0) at planner.c:656
    656   inline_set_returning_functions(root);
    (gdb) c
    Continuing.
    #ANY类型并没有做上拉操作
    

    五、小结

    1、基本概念:subLink的基本概念以及基本分类;
    2、函数:Planner的主函数简要介绍;
    3、数据结构:SubLink、SubLinkType等结构;
    4、上拉操作:只对ANY/EXISTS进行处理,其他类型如ALL暂不处理。

    来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/6906/viewspace-2374890/,如需转载,请注明出处,否则将追究法律责任。

    转载于:http://blog.itpub.net/6906/viewspace-2374890/

    展开全文
  • 版权声明:本文为CSDN博主「陈永佳」的原创文章原文链接:https://blog.csdn.net/Mrs_chens/article/details/104315412????摘要在使用msyql进行模糊查询的时候,很自然的会用到like语句,通常情况下,在数据量小的...

    版权声明:本文为CSDN博主「陈永佳」的原创文章

    原文链接:https://blog.csdn.net/Mrs_chens/article/details/104315412

    📖摘要

    在使用msyql进行模糊查询的时候,很自然的会用到like语句,通常情况下,在数据量小的时候,不容易看出查询的效率,但在数据量达到百万级,千万级的时候,查询的效率就很容易显现出来。这个时候查询的效率就显得很重要!

    😱LIKE查询

    一般情况下like模糊查询的写法为(field已建立索引):

    SELECT `column` FROM `table` WHERE `field` like '%keyword%';

    上面的语句用explain解释来看,SQL语句并未用到索引,而且是全表搜索,如果在数据量超大的时候,可想而知最后的效率会是这样

    对比下面的写法:

    SELECT `column` FROM `table` WHERE `field` like 'keyword%';

    这样的写法用explain解释看到,SQL语句使用了索引,搜索的效率大大的提高了!

    但是有的时候,我们在做模糊查询的时候,并非要想查询的关键词都在开头,所以如果不是特别的要求,"keywork%"并不合适所有的模糊查询

    这个时候,我们可以考虑用其他的方法

    LOCATE('substr',str,pos)方法

    SELECT LOCATE('xbar',`foobar`);

    ###返回0

    SELECT LOCATE('bar',`foobarbar`);

    ###返回4

    SELECT LOCATE('bar',`foobarbar`,5);

    ###返回7

    备注:返回 substr 在 str 中第一次出现的位置,如果 substr 在 str 中不存在,返回值为 0 。如果pos存在,返回 substr 在 str 第pos个位置后第一次出现的位置,如果 substr 在 str 中不存在,返回值为0。

    SELECT `column` FROM `table` WHERE LOCATE('keyword', `field`)>0

    备注:keyword是要搜索的内容,field为被匹配的字段,查询出所有存在keyword的数据

    🌂优化

    数据如下

    d23104b5380d49b4b983f4b9b8372799.png

    一、POSITION('substr' INfield)方法

    position可以看做是locate的别名,功能跟locate一样

    SELECT `key`,cpnKey,pincodeProductKey FROM hotkidclub_draw.`cpn_pool` WHERE POSITION('2' IN `pincodeProductKey`);

    7e80749e32daecb146cc95c5af3dbc17.png

    二、INSTR(str,'substr')方法

    SELECT `key`,cpnKey,pincodeProductKey FROM hotkidclub_draw.`cpn_pool` WHERE INSTR(`pincodeProductKey`, '2' )>0 ;

    0e78086542281afae6e9bb1377c734b2.png

    三、除了上述的方法外,还有一个函数FIND_IN_SET('值',filed);

    返回str2中str1所在的位置索引,其中str2必须以","分割开。

    SELECT `key`,cpnKey,pincodeProductKey FROM hotkidclub_draw.`cpn_pool` WHERE FIND_IN_SET('2',`pincodeProductKey`);

    1dcad75a48faa2531bb37e2b98d12447.png

    展开全文
  • 启动excel,点击data选项卡,在这个选项卡下选择new query,from other...解释一下:test1是我的mysql一个数据库的名字,biao1是我的test1数据库里面的一张表,表的名字是用引号引起来,不是引号,这一点一定要注意...

    启动excel,点击data选项卡,在这个选项卡下选择new query,from other sources,form odbc

    d9e7ea330abdfac6fff7082ac36c5114.png

    然后点击advanced options选项,填入如下查询语句

    select * from test1.`biao1`;

    解释一下:

    test1是我的mysql一个数据库的名字,biao1是我的test1数据库里面的一张表,表的名字是用反引号引起来,

    不是引号,这一点一定要注意。

    e44d41d4d365306b42a109aa30b3fd9f.png

    然后点击OK,查询结果就出来了

    4f65e59d1627bdf3e6a54f9f57cfe870.png

    我们可以对数据进行进一步的加工。

    注意:不需要填写connection string那一栏,如果非要填写,可以像我下面这样填写

    Driver={MySQL ODBC 8.0 Unicode Driver};Server=localhost;Database=test1

    如果填写了connection string这一栏,那么data source name那里可以填None,也可以。

    98bb4d7168c3ff29a3b65f579b6eb607.png

    查询的结果是一样的,如下图所示

    06bdc81f758753d16ccf4b4465d01796.png

    展开全文
  • 4、重点:添加站长工具,添加PR真假查询\ALEXA流量查询\百度指数查询\网站链查询\历史记录查询\网站备案查询\域名历史查询\域名Whois查询\同IP网站查询\反向链接查询\死链接检测等站长常用工具,站长工具集合站长...
  • 所有做搜索引擎优化的人都肯定要时不时的查询某个网页或某个域名的反向链接,不光是自己的网站,也会查竞争对手的网站。有很多方法可以查反向链接,主要都是...谷歌搜索引擎查链:通过link命令查询的反向链接,现在来
  • 媒体查询

    2017-02-16 13:26:56
    语法:@media logic type ...only关键字可以确保旧的浏览器不读取余下的媒体查询,同时一并忽略链接的样式表;not关键字可以对媒体查询的结构求,让其反面为真; type:类型,screen、print等; feature:value对是可
  • 可查询同时查询无数个域名是否备案(无需要验证码)/百度收录批量查询/百度链批量查询,同时查询无数个域名的百度链情况,这个主要方便喜欢抢注域名的朋友/网站出站链接查询,可以同时查询无数个站点的出站情况/...
  • 可同时查询无数个域名的百度链情况,这个主要方便喜欢抢注域名的朋友/网站出站链接查询 可同时查询无数个站点的出站情况/ALEXA世界排名批量查询/雅虎链批量查询 可同时查询所有域名的网络中有多少外连接本站/站点...
  • 本工具能很好的查到您的网站在网络的什么地方留有链接(非百度链,百度链有的只有您的链接但是不能打开)并通过这些链接直接能访问到您的站点页面。包括查询总外链数,列出一千条链接页面提供您查看。如果您发现...
  • 需求:图片链接插入和修改切除图片的头部信息,查询的时候添加头部信息 解决办法:自定义注解在图片链接字段上,在序列化和序列化是根据注解标记添加或者切除图片头部链接 jackson序列化 jackson序列化需要在...
  • 最近搞SEO,让自己学了不少东西。 最近同事一直纠结外链和...外链:也叫外部链接,或者是导入链接,个人认为外链即能够给你带来蜘蛛爬行访问的链接就叫做外链,也就是说从网站外部的其他网页链接到你的网站的链接。...
  • SEO 中谈到的反向链接又叫导入链接(Backlinks),外部链接。但反向链接的概括包括了站内和站外的导入链接。  简单概括如下:有几个网页链接指向你的站,你就有了几个反向链接。...可以同时查询网站所有内页的
  • 可以显示网站收录数和反向链接数,包括的搜索引擎有:百度、...查询网站收录数和反向链接数,包括的搜索引擎有:百度、谷歌、雅虎、搜狗、搜搜、有道和必应。SEO工具。 2013-05-01 更新了下数据 支持语言:中文 (简体)
  • 大多数开发人员听说过关于模式的一个很好的例子:结构化查询语言(Structured Query Language,SQL)的错误使用导致 Web 站点受到 SQL 注入攻击。这种模式使得公司损失惨重,并暴露了客户...
  • 符号链接转设备名可以调用ZwOpenSymbolicLinkObject,ZwQuerySymbolicLinkObject直接查询到设备名 过来是调用第一种方法,把每个盘符A到Z的符号链接对应的设备名求出来,然后一一比对。 一种实现 DWORD ...
  • 4、重点:添加站长工具,添加PR真假查询\ALEXA流量查询\百度指数查询\网站链查询\历史记录查询\网站备案查询\域名历史查询\域名Whois查询\同IP网站查询\反向链接查询\死链接检测等站长常用工具,站长工具集合站长...
  • (2)MySQL中的字段名和关键字重名时,要使用“`”(引号)查询,而sqlserver中时“[]”(中括号)。 (3)java 插入数据到MySQL中时,中文乱码问题,网上看了许多解决方法, 一是在数据库地址(URL)链接时...
  • 一个静态库(.a),或者 可执行文件(动态链接库没试过),可以使用下面的命令查询: 一、有哪些符号: Linux平台(包括armcc和gcc编译的二进制文件):nm file_name 二、汇编: GCC编译的二进制: objdump -D ...
  • 原文链接 可恶的爬虫直接把生产6台机器爬挂了! 引言 正在午睡,突然收到线上疯狂报警的邮件,查看这个邮件发现这个报警的应用最近半个月都没有发布,应该不至于会有报警,但是还是打开邮件通过监控发现是由于...
  • 40、经lgooxc站长测试使用整合包独立开站,只需要一个月google链进百万,PR值达到4,alexa世界排名进10位,www.alexa.gz.cn可测试。 41、以上四站整合包在www.alexa.gz.cn站下方有下载,最新版都将在此站下方发布 ...
  • 巨匠都知道,在百度使用令所查询到的经常都是以文本体例泛起的反向链接,这就是百度链的表达体式格局。若是百度对不在意的,那末为什么要泛起这个成分呢?而且网站具有少量的百度相关域对网站排名权重都有必然的...

空空如也

空空如也

1 2 3 4 5 ... 17
收藏数 322
精华内容 128
关键字:

反链接查询