Postgresql源码(127)投影ExecProject的表达式执行分析

无论是投影还是别的计算,表达式执行的入口和计算逻辑都是统一的,这里已投影为分析表达式执行的流程。

1 投影函数

用例

create table t1(i int primary key, j int, k int);
insert into t1 select i, i % 10, i % 100 from generate_series(1,10000000) t(i);
explain analyze select abs(k),abs(k),abs(k),abs(k),abs(k),exp(k),exp(k),exp(k),exp(k),exp(k) from t1;

对于这样这一条查询来说,每扫描一行,都会调用投影函数ExecProject,完成最终结果的构造。

投影函数:

static inline TupleTableSlot *
ExecProject(ProjectionInfo *projInfo)
{
	ExprContext *econtext = projInfo->pi_exprContext;
	ExprState  *state = &projInfo->pi_state;
	TupleTableSlot *slot = state->resultslot;
	bool		isnull;

	/*
	 * Clear any former contents of the result slot.  This makes it safe for
	 * us to use the slot's Datum/isnull arrays as workspace.
	 */
	ExecClearTuple(slot);

	/* Run the expression, discarding scalar result from the last column. */
	(void) ExecEvalExprSwitchContext(state, econtext, &isnull);

	/*
	 * Successfully formed a result row.  Mark the result slot as containing a
	 * valid virtual tuple (inlined version of ExecStoreVirtualTuple()).
	 */
	slot->tts_flags &= ~TTS_FLAG_EMPTY;
	slot->tts_nvalid = slot->tts_tupleDescriptor->natts;

	return slot;
}

总结:

  • projInfo->pi_exprContext记录了需要执行表达式的上下文信息
    • 具体存放:t1表扫出来的一行
    • 具体存放:表达式执行的内存上下文
  • projInfo->pi_state记录了表达式执行状态
    • 具体存放:表达式执行的每一个step,每一个step放到ExecInterpExpr中按顺序执行得到最终结果tuple。

2.1 表达式执行上下文结构ExprContext

其中ecxt_scantuple用来保存待处理输入tuple,通常指向一个 tuple table slot。

ExprContext *econtext = {
  type = T_ExprContext,
  ecxt_scantuple = 0x1520918,    <<<<<<<< 待处理tuple
  ecxt_innertuple = 0x0,
  ecxt_outertuple = 0x0,
  ecxt_per_query_memory = 0x15203e0,
  ecxt_per_tuple_memory = 0x151e3d0,
  ecxt_param_exec_vals = 0x0,
  ecxt_param_list_info = 0x0,
  ecxt_aggvalues = 0x0,
  ecxt_aggnulls = 0x0,
  caseValue_datum = 0,
  caseValue_isNull = true,
  domainValue_datum = 0,
  domainValue_isNull = true,
  ecxt_estate = 0x15204e0,
  ecxt_callbacks = 0x0
}

2.2 表达式执行状态ExprState

ExprState  *state = {
  type = T_ExprState,
  flags = 6 '\006',
  resnull = false,
  resvalue = 0,
  resultslot = 0x151f278,
  steps = 0x1525c38,
  evalfunc = 0x74d749 <ExecInterpExprStillValid>,
  expr = 0x24c9618,
  evalfunc_private = 0x74af83 <ExecInterpExpr>,
  steps_len = 37,
  steps_alloc = 64,
  parent = 0x151e718,
  ext_params = 0x0,
  innermost_caseval = 0x0,
  innermost_casenull = 0x0,
  innermost_domainval = 0x0,
  innermost_domainnull = 0x0,
  escontext = 0x0
}

注意实际执行使用ExecInterpExpr函数完成表达式计算:

2.3 执行表达式

执行时,通过state->evalfunc函数完成具体的表达式计算动作。具体怎么计算流程放在steps中:

(gdb) p/x state->steps[0]->opcode
$15 = 0x74b0ad
(gdb) p/x state->steps[1]->opcode
$16 = 0x74b1ec
(gdb) p/x state->steps[2]->opcode
$17 = 0x74b784
(gdb) p/x state->steps[3]->opcode
$18 = 0x74b591
(gdb) p/x state->steps[4]->opcode
$19 = 0x74b1ec
(gdb) p/x state->steps[5]->opcode
$20 = 0x74b784
(gdb) p/x state->steps[6]->opcode
$21 = 0x74b591
(gdb) p/x state->steps[7]->opcode
$22 = 0x74b1ec
...
...

opcode需要再reverse_dispatch_table中确定当前计算走哪个ExecInterpExpr中的分支:

(这里不太方便调试因为这里把一个超大的switch case改成了goto,为了性能!)

p reverse_dispatch_table
$13 = {{
    opcode = 0x74b01a <ExecInterpExpr+151>,
    op = EEOP_DONE
  }, {
    opcode = 0x74b041 <ExecInterpExpr+190>,
    op = EEOP_INNER_FETCHSOME
  }, {
    opcode = 0x74b077 <ExecInterpExpr+244>,
    op = EEOP_OUTER_FETCHSOME
  }, {
    opcode = 0x74b0ad <ExecInterpExpr+298>,
    op = EEOP_SCAN_FETCHSOME
  }, {
    opcode = 0x74b0e6 <ExecInterpExpr+355>,
    op = EEOP_INNER_VAR
  }, {
    opcode = 0x74b169 <ExecInterpExpr+486>,
    op = EEOP_OUTER_VAR
  }, {
    opcode = 0x74b1ec <ExecInterpExpr+617>,
    op = EEOP_SCAN_VAR
  }, {
    opcode = 0x74b26f <ExecInterpExpr+748>,
    op = EEOP_INNER_SYSVAR
  }, {
    opcode = 0x74b29e <ExecInterpExpr+795>,
    op = EEOP_OUTER_SYSVAR
  }, {
    opcode = 0x74b2cd <ExecInterpExpr+842>,
    op = EEOP_SCAN_SYSVAR
  }, {
    opcode = 0x74b2fc <ExecInterpExpr+889>,
    op = EEOP_WHOLEROW
  }, {
    opcode = 0x74b32a <ExecInterpExpr+935>,
    op = EEOP_ASSIGN_INNER_VAR
  }, {
    opcode = 0x74b3f7 <ExecInterpExpr+1140>,
    op = EEOP_ASSIGN_OUTER_VAR
  }, {
    opcode = 0x74b4c4 <ExecInterpExpr+1345>,
    op = EEOP_ASSIGN_SCAN_VAR
  }, {
    opcode = 0x74b591 <ExecInterpExpr+1550>,
    op = EEOP_ASSIGN_TMP
  }, {
    opcode = 0x74b615 <ExecInterpExpr+1682>,
    op = EEOP_ASSIGN_TMP_MAKE_RO
  }, {
    opcode = 0x74b6e1 <ExecInterpExpr+1886>,
    op = EEOP_CONST
  }, {
    opcode = 0x74b717 <ExecInterpExpr+1940>,
    op = EEOP_FUNCEXPR
  }, {
    opcode = 0x74b784 <ExecInterpExpr+2049>,
    op = EEOP_FUNCEXPR_STRICT
  }, {
    opcode = 0x74b853 <ExecInterpExpr+2256>,
    op = EEOP_FUNCEXPR_FUSAGE
  }, {
    opcode = 0x74b881 <ExecInterpExpr+2302>,
    op = EEOP_FUNCEXPR_STRICT_FUSAGE
  }, {
    opcode = 0x74b8af <ExecInterpExpr+2348>,
    op = EEOP_BOOL_AND_STEP_FIRST
  }, {
    opcode = 0x74b8ba <ExecInterpExpr+2359>,
    op = EEOP_BOOL_AND_STEP
  }, {
    opcode = 0x74b92c <ExecInterpExpr+2473>,
    op = EEOP_BOOL_AND_STEP_LAST
  }, {
    opcode = 0x74b98f <ExecInterpExpr+2572>,
    op = EEOP_BOOL_OR_STEP_FIRST
  }, {
    opcode = 0x74b99a <ExecInterpExpr+2583>,
    op = EEOP_BOOL_OR_STEP
  }, {
    opcode = 0x74ba09 <ExecInterpExpr+2694>,
    op = EEOP_BOOL_OR_STEP_LAST
  }, {
    opcode = 0x74ba69 <ExecInterpExpr+2790>,
    op = EEOP_BOOL_NOT_STEP
  }, {
    opcode = 0x74bab3 <ExecInterpExpr+2864>,
    op = EEOP_QUAL
  }, {
    opcode = 0x74bb38 <ExecInterpExpr+2997>,
    op = EEOP_JUMP
  }, {
    opcode = 0x74bb63 <ExecInterpExpr+3040>,
    op = EEOP_JUMP_IF_NULL
  }, {
    opcode = 0x74bbae <ExecInterpExpr+3115>,
    op = EEOP_JUMP_IF_NOT_NULL
  }, {
    opcode = 0x74bbfc <ExecInterpExpr+3193>,
    op = EEOP_JUMP_IF_NOT_TRUE
  }, {
    opcode = 0x74bc61 <ExecInterpExpr+3294>,
    op = EEOP_NULLTEST_ISNULL
  }, {
    opcode = 0x74bc9d <ExecInterpExpr+3354>,
    op = EEOP_NULLTEST_ISNOTNULL
  }, {
    opcode = 0x74bcea <ExecInterpExpr+3431>,
    op = EEOP_NULLTEST_ROWISNULL
  }, {
    opcode = 0x74bd18 <ExecInterpExpr+3477>,
    op = EEOP_NULLTEST_ROWISNOTNULL
  }, {
    opcode = 0x74bd46 <ExecInterpExpr+3523>,
    op = EEOP_BOOLTEST_IS_TRUE
  }, {
    opcode = 0x74bd86 <ExecInterpExpr+3587>,
    op = EEOP_BOOLTEST_IS_NOT_TRUE
  }, {
    opcode = 0x74be01 <ExecInterpExpr+3710>,
    op = EEOP_BOOLTEST_IS_FALSE
  }, {
    opcode = 0x74be7c <ExecInterpExpr+3833>,
    op = EEOP_BOOLTEST_IS_NOT_FALSE
  }, {
    opcode = 0x74bebc <ExecInterpExpr+3897>,
    op = EEOP_PARAM_EXEC
  }, {
    opcode = 0x74beea <ExecInterpExpr+3943>,
    op = EEOP_PARAM_EXTERN
  }, {
    opcode = 0x74bf18 <ExecInterpExpr+3989>,
    op = EEOP_PARAM_CALLBACK
  }, {
    opcode = 0x74bf48 <ExecInterpExpr+4037>,
    op = EEOP_CASE_TESTVAL
  }, {
    opcode = 0x74bfbe <ExecInterpExpr+4155>,
    op = EEOP_DOMAIN_TESTVAL
  }, {
    opcode = 0x74c034 <ExecInterpExpr+4273>,
    op = EEOP_MAKE_READONLY
  }, {
    opcode = 0x74c08a <ExecInterpExpr+4359>,
    op = EEOP_IOCOERCE
  }, {
    opcode = 0x74c26c <ExecInterpExpr+4841>,
    op = EEOP_IOCOERCE_SAFE
  }, {
    opcode = 0x74c293 <ExecInterpExpr+4880>,
    op = EEOP_DISTINCT
  }, {
    opcode = 0x74c3a6 <ExecInterpExpr+5155>,
    op = EEOP_NOT_DISTINCT
  }, {
    opcode = 0x74c496 <ExecInterpExpr+5395>,
    op = EEOP_NULLIF
  }, {
    opcode = 0x74c57f <ExecInterpExpr+5628>,
    op = EEOP_SQLVALUEFUNCTION
  }, {
    opcode = 0x74c5a6 <ExecInterpExpr+5667>,
    op = EEOP_CURRENTOFEXPR
  }, {
    opcode = 0x74c5cd <ExecInterpExpr+5706>,
    op = EEOP_NEXTVALUEEXPR
  }, {
    opcode = 0x74c5f4 <ExecInterpExpr+5745>,
    op = EEOP_ARRAYEXPR
  }, {
    opcode = 0x74c61b <ExecInterpExpr+5784>,
    op = EEOP_ARRAYCOERCE
  }, {
    opcode = 0x74c649 <ExecInterpExpr+5830>,
    op = EEOP_ROW
  }, {
    opcode = 0x74c670 <ExecInterpExpr+5869>,
    op = EEOP_ROWCOMPARE_STEP
  }, {
    opcode = 0x74c7be <ExecInterpExpr+6203>,
    op = EEOP_ROWCOMPARE_FINAL
  }, {
    opcode = 0x74c8cf <ExecInterpExpr+6476>,
    op = EEOP_MINMAX
  }, {
    opcode = 0x74c8f6 <ExecInterpExpr+6515>,
    op = EEOP_FIELDSELECT
  }, {
    opcode = 0x74c924 <ExecInterpExpr+6561>,
    op = EEOP_FIELDSTORE_DEFORM
  }, {
    opcode = 0x74c952 <ExecInterpExpr+6607>,
    op = EEOP_FIELDSTORE_FORM
  }, {
    opcode = 0x74c980 <ExecInterpExpr+6653>,
    op = EEOP_SBSREF_SUBSCRIPTS
  }, {
    opcode = 0x74c9df <ExecInterpExpr+6748>,
    op = EEOP_SBSREF_OLD
  }, {
    opcode = 0x74c9e1 <ExecInterpExpr+6750>,
    op = EEOP_SBSREF_ASSIGN
  }, {
    opcode = 0x74c9e1 <ExecInterpExpr+6750>,
    op = EEOP_SBSREF_FETCH
  }, {
    opcode = 0x74ca11 <ExecInterpExpr+6798>,
    op = EEOP_CONVERT_ROWTYPE
  }, {
    opcode = 0x74ca3f <ExecInterpExpr+6844>,
    op = EEOP_SCALARARRAYOP
  }, {
    opcode = 0x74ca66 <ExecInterpExpr+6883>,
    op = EEOP_HASHED_SCALARARRAYOP
  }, {
    opcode = 0x74ca94 <ExecInterpExpr+6929>,
    op = EEOP_DOMAIN_NOTNULL
  }, {
    opcode = 0x74cabb <ExecInterpExpr+6968>,
    op = EEOP_DOMAIN_CHECK
  }, {
    opcode = 0x74cae2 <ExecInterpExpr+7007>,
    op = EEOP_XMLEXPR
  }, {
    opcode = 0x74cb09 <ExecInterpExpr+7046>,
    op = EEOP_JSON_CONSTRUCTOR
  }, {
    opcode = 0x74cb37 <ExecInterpExpr+7092>,
    op = EEOP_IS_JSON
  }, {
    opcode = 0x74cb5e <ExecInterpExpr+7131>,
    op = EEOP_JSONEXPR_PATH
  }, {
    opcode = 0x74cb9f <ExecInterpExpr+7196>,
    op = EEOP_JSONEXPR_COERCION
  }, {
    opcode = 0x74cbcd <ExecInterpExpr+7242>,
    op = EEOP_JSONEXPR_COERCION_FINISH
  }, {
    opcode = 0x74cbf4 <ExecInterpExpr+7281>,
    op = EEOP_AGGREF
  }, {
    opcode = 0x74cc82 <ExecInterpExpr+7423>,
    op = EEOP_GROUPING_FUNC
  }, {
    opcode = 0x74cca9 <ExecInterpExpr+7462>,
    op = EEOP_WINDOW_FUNC
  }, {
    opcode = 0x74cd40 <ExecInterpExpr+7613>,
    op = EEOP_MERGE_SUPPORT_FUNC
  }, {
    opcode = 0x74cd6e <ExecInterpExpr+7659>,
    op = EEOP_SUBPLAN
  }, {
    opcode = 0x74cd9c <ExecInterpExpr+7705>,
    op = EEOP_AGG_STRICT_DESERIALIZE
  }, {
    opcode = 0x74cdd7 <ExecInterpExpr+7764>,
    op = EEOP_AGG_DESERIALIZE
  }, {
    opcode = 0x74ce8a <ExecInterpExpr+7943>,
    op = EEOP_AGG_STRICT_INPUT_CHECK_ARGS
  }, {
    opcode = 0x74cf18 <ExecInterpExpr+8085>,
    op = EEOP_AGG_STRICT_INPUT_CHECK_NULLS
  }, {
    opcode = 0x74cf9f <ExecInterpExpr+8220>,
    op = EEOP_AGG_PLAIN_PERGROUP_NULLCHECK
  }, {
    opcode = 0x74d02c <ExecInterpExpr+8361>,
    op = EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL
  }, {
    opcode = 0x74d147 <ExecInterpExpr+8644>,
    op = EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL
  }, {
    opcode = 0x74d22c <ExecInterpExpr+8873>,
    op = EEOP_AGG_PLAIN_TRANS_BYVAL
  }, {
    opcode = 0x74d2fb <ExecInterpExpr+9080>,
    op = EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF
  }, {
    opcode = 0x74d413 <ExecInterpExpr+9360>,
    op = EEOP_AGG_PLAIN_TRANS_STRICT_BYREF
  }, {
    opcode = 0x74d4f5 <ExecInterpExpr+9586>,
    op = EEOP_AGG_PLAIN_TRANS_BYREF
  }, {
    opcode = 0x74d5c1 <ExecInterpExpr+9790>,
    op = EEOP_AGG_PRESORTED_DISTINCT_SINGLE
  }, {
    opcode = 0x74d648 <ExecInterpExpr+9925>,
    op = EEOP_AGG_PRESORTED_DISTINCT_MULTI
  }, {
    opcode = 0x74d6cf <ExecInterpExpr+10060>,
    op = EEOP_AGG_ORDERED_TRANS_DATUM
  }, {
    opcode = 0x74d6fd <ExecInterpExpr+10106>,
    op = EEOP_AGG_ORDERED_TRANS_TUPLE
  }}

翻译后

(gdb) p/x state->steps[0]->opcode
$15 = 0x74b0ad                       EEOP_SCAN_FETCHSOME
(gdb) p/x state->steps[1]->opcode
$16 = 0x74b1ec                       EEOP_SCAN_VAR
(gdb) p/x state->steps[2]->opcode
$17 = 0x74b784                       EEOP_FUNCEXPR_STRICT
(gdb) p/x state->steps[3]->opcode
$18 = 0x74b591                       EEOP_ASSIGN_TMP
(gdb) p/x state->steps[4]->opcode
$19 = 0x74b1ec                       EEOP_SCAN_VAR
(gdb) p/x state->steps[5]->opcode
$20 = 0x74b784                       EEOP_FUNCEXPR_STRICT
(gdb) p/x state->steps[6]->opcode
$21 = 0x74b591                       EEOP_ASSIGN_TMP
(gdb) p/x state->steps[7]->opcode
$22 = 0x74b1ec                       EEOP_SCAN_VAR
...
...
(gdb) p/x state->steps[34]->opcode
$27 = 0x74b784                       EEOP_FUNCEXPR_STRICT
(gdb) p/x state->steps[35]->opcode
$28 = 0x74b591                       EEOP_ASSIGN_TMP
(gdb) p/x state->steps[36]->opcode
$29 = 0x74b01a                       EEOP_DONE

可以看到表达式计算的流程:

第一步:EEOP_SCAN_FETCHSOME
  1. 从econtext->ecxt_scantuple读取到scanslot(当前要处理的一行数据)
  2. slot_getsomeattrs函数确保这一行数据中,至少有op->d.fetch.last_var个列是可以直接访问的(这里是3,因为t1表就三列,后面的处理可能需要访问这三列的任意一列)。为什么说有时不能直接访问,因为列有可能指向toast表。
		EEO_CASE(EEOP_SCAN_FETCHSOME)
		{
			CheckOpSlotCompatibility(op, scanslot);

			slot_getsomeattrs(scanslot, op->d.fetch.last_var);

			EEO_NEXT();
		}
第二步:EEOP_SCAN_VAR

输入

p state->steps[1].d.fetch
$46 = {
  last_var = 2,
  fixed = 23,
  known_desc = 0x0,
  kind = 0x0
}

执行,从行中拿到第2列的值(0列、1列、2列)

		EEO_CASE(EEOP_SCAN_VAR)
		{
			int			attnum = op->d.var.attnum;   // attnum = 2

			/* See EEOP_INNER_VAR comments */

			Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
			*op->resvalue = scanslot->tts_values[attnum];
			*op->resnull = scanslot->tts_isnull[attnum];

			EEO_NEXT();
		}

结果

(gdb) p state->steps[1].resvalue
$41 = (Datum *) 0x151f918
(gdb) p *state->steps[1].resvalue
$39 = 1

(gdb) p state->steps[1].resnull
$42 = (_Bool *) 0x151f920
(gdb) p *state->steps[1].resnull
$40 = false
第三步:EEOP_FUNCEXPR_STRICT

输入

(gdb) p state->steps[2].d.func
$47 = {
  finfo = 0x151f8a8,
  fcinfo_data = 0x151f8f8,
  fn_addr = 0xa8ea89 <int4abs>,
  nargs = 1
}

执行

		EEO_CASE(EEOP_FUNCEXPR_STRICT)
		{
			FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
			NullableDatum *args = fcinfo->args;
			int			nargs = op->d.func.nargs;
			Datum		d;

			/* strict function, so check for NULL args */
			for (int argno = 0; argno < nargs; argno++)
			{
				if (args[argno].isnull)
				{
					*op->resnull = true;
					goto strictfail;
				}
			}
			fcinfo->isnull = false;
			d = op->d.func.fn_addr(fcinfo);
			*op->resvalue = d;
			*op->resnull = fcinfo->isnull;

	strictfail:
			EEO_NEXT();
		}

注意这里有一个地方很有意思,按理说EEOP_SCAN_VAR执行完才把值拿到,但从EEOP_FUNCEXPR_STRICT的执行来看,并没有发现把前一步的结果,放到函数args的步骤。

但是从GDB来看,函数的入参的地址和上一步取值后存放结果的地址是相同的,也就是上一步取值就是为了拿入参的args:

(gdb) p state->steps[4].resvalue
$59 = (Datum *) 0x151f9b8

(gdb) p state->steps[5].d.func->fcinfo_data->args
$58 = 0x151f9b8

具体是怎么做到的呢?在构造steps时:
在这里插入图片描述
对于函数入参value会调用ExecInitExprRec去取值,在这个过程中,把参数的value指向新step的resvalue:
在这里插入图片描述
而这个新的step就是EEOP_SCAN_VAR:
在这里插入图片描述

第四步:暂存结果集

暂存结果集到resultslot中:

		EEO_CASE(EEOP_ASSIGN_TMP)
		{
			int			resultnum = op->d.assign_tmp.resultnum;

			Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
			resultslot->tts_values[resultnum] = state->resvalue;
			resultslot->tts_isnull[resultnum] = state->resnull;

			EEO_NEXT();
		}
第五步:继续上述流程直到执行完成
(gdb) p/x state->steps[0]->opcode
$15 = 0x74b0ad                       EEOP_SCAN_FETCHSOME   第一步
(gdb) p/x state->steps[1]->opcode
$16 = 0x74b1ec                       EEOP_SCAN_VAR         第二步
(gdb) p/x state->steps[2]->opcode
$17 = 0x74b784                       EEOP_FUNCEXPR_STRICT  第三步
(gdb) p/x state->steps[3]->opcode
$18 = 0x74b591                       EEOP_ASSIGN_TMP       第四步
(gdb) p/x state->steps[4]->opcode
$19 = 0x74b1ec                       EEOP_SCAN_VAR         第五步 和上述流程相同,每个函数的执行流程都是相似的
(gdb) p/x state->steps[5]->opcode
$20 = 0x74b784                       EEOP_FUNCEXPR_STRICT
(gdb) p/x state->steps[6]->opcode
$21 = 0x74b591                       EEOP_ASSIGN_TMP
(gdb) p/x state->steps[7]->opcode
$22 = 0x74b1ec                       EEOP_SCAN_VAR
...
...
(gdb) p/x state->steps[34]->opcode
$27 = 0x74b784                       EEOP_FUNCEXPR_STRICT
(gdb) p/x state->steps[35]->opcode
$28 = 0x74b591                       EEOP_ASSIGN_TMP
(gdb) p/x state->steps[36]->opcode
$29 = 0x74b01a                       EEOP_DONE

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/586017.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JeeSite框架安装部署

下载JeeSite框架。 依次执行两个sql文件。 如果是mysql8.0&#xff0c;则create_user.sql需要改成下面的内容&#xff1a; -- 打开 my.ini 给 [mysqld] 增加如下配置&#xff1a; -- sql_modeONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREAT…

YOLOv8核心原理深度解析

YOLOv8源码地址: https://github.com/ultralytics/ultralytics 一、简介: 根据官方描述,Yolov8是一个SOTA模型,它建立在Yolo系列历史版本的基础上,并引入了新的功能和改进点,以进一步提升性能和灵活性,使其成为实现目标检测、图像分割、姿态估计等任务的最佳选择。其具体…

代码随想录——双指针与滑动窗口(四)

一.1423. 可获得的最大点数 题目详情 解题思路 这里我们每次只能取最左或最右边的卡牌,第一反应其实是使用双指针&#xff0c;通过局部贪心来解决&#xff0c;但是如果两边相等的话用局部贪心无法来判断到底取哪一边&#xff0c;那我们不妨换一个思路&#xff1a; 我们首先任…

DICOM 测试工具

一个DICOM测试工具。 引用了 fo-dicom 。fo-dicom 算是比较好用的&#xff0c;我的另外一个项目也是用了它。 using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; …

Go语言map

map 概念 在Go语言中&#xff0c;map 是一种内建的数据结构&#xff0c;它提供了一种关联式的存储机制&#xff0c;允许你以键值对的形式存储数据。每个键都是唯一的&#xff0c;并且与一个值相关联。你可以通过键来查找、添加、更新和删除值&#xff0c;这类似于其他编程语言…

Spring Boot的热部署工具“AND”Swagger测试工具

Spring Boot的热部署&Swagger测试页面的使用 热部署指的是在项目无需重启的情况下&#xff0c;只需要刷新页面&#xff0c;即可获得已经修改的样式或功能。要注意该工具一般用于开发环境&#xff0c;在生产环境中最好不要添加这个工具。 对于无需重启便可刷新这么方便的工…

小剧场短剧影视小程序源码_后端PHP

项目运行截图 源码贡献 https://githubs.xyz/boot?app42 部署说明 linux/win任选 PHP版本&#xff1a;7.3/7.2&#xff08;测试时我用的7.2要安装sg扩展 &#xff09; 批量替换域名http://video.owoii.com更换为你的 批量替换域名http://120.79.77.163:1更换为你的 这两个…

交通运输智慧监管平台---强化物流安全与效率的新举措

一、建设背景 随着社会对于交通安全和环境保护的要求不断提高&#xff0c;对卡车运输的监管和合规性要求也逐渐加强。为了满足快速发展的物流需求&#xff0c;提高供应链协同和可追溯性、解决安全问题、提高运输效率和降低成本&#xff0c;我们利用现代技术和信息化手段着力建设…

Spark SQL编程初级实践

参考链接 Spark编程: Spark SQL基本操作 2020.11.01_df.agg("age"->"avg")-CSDN博客 RDD编程初级实践-CSDN博客 Spark和Hadoop的安装-CSDN博客 1. Spark SQL基本操作 { "id":1 , "name":" Ella" , "age":…

数字电路-5路呼叫显示和8路抢答器

本内容涉及两个电路&#xff0c;分别为5路呼叫显示电路和8路抢答器电路&#xff0c;包含Multisim仿真原文件&#xff0c;为掌握FPGA做个铺垫。紫色文字是超链接&#xff0c;点击自动跳转至相关博文。持续更新&#xff0c;原创不易&#xff01; 目录&#xff1a; 一、5路呼叫显…

每日OJ题_DFS爆搜深搜回溯剪枝②_力扣526. 优美的排列

目录 力扣526. 优美的排列 解析代码 力扣526. 优美的排列 526. 优美的排列 难度 中等 假设有从 1 到 n 的 n 个整数。用这些整数构造一个数组 perm&#xff08;下标从 1 开始&#xff09;&#xff0c;只要满足下述条件 之一 &#xff0c;该数组就是一个 优美的排列 &#…

nginx缓存清理

背景 昨天打开我的gpt镜像网站&#xff0c;意外发现静态图片资源全都无法获取了 CoCo-AI 一番排查下来&#xff0c;发现是引用的cdn链接失效了 且cdn源是属于七牛云的&#xff0c;且不再维护&#xff0c;于是果断切换到cloudflare export function getEmojiUrl(unified: str…

JavaScript中的Object方法、Array方法、String方法

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;JavaScript 精粹 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 &#x1f525;Object方法&#x1f31e;1 Object.is()&#x1f31e;2 Object.…

区块链 | 由外部实体导致的 NFT 安全问题

&#x1f98a;原文&#xff1a; Understanding Security Issues in the NFT Ecosystem &#x1f98a;警告&#xff1a; 本文只记录了原文的第 6 节。 1 问题描述 NFT 所指向的数字资产&#xff08;图片、视频等&#xff09;必须是可以访问的&#xff0c;这样 NFT 才具有意义…

iA Writer for Mac:简洁强大的写作软件

在追求高效写作的今天&#xff0c;iA Writer for Mac凭借其简洁而强大的功能&#xff0c;成为了许多作家、记者和学生的首选工具。这款专为Mac用户打造的写作软件&#xff0c;以其独特的设计理念和实用功能&#xff0c;助你轻松打造高质量的文章。 iA Writer for Mac v7.1.2中文…

数据挖掘之基于Lightgbm等多模型消融实验的信用欺诈检测实现

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 在当前的金融环境中&#xff0c;信用欺诈行为日益增多&#xff0c;给金融机构和消费者带来了巨大的损…

ThingsBoard PE专业版解决方案技术文档——温度湿度

1、项目总览 2、设备接入 3、设备告警 3.1 高温告警 创建一个Flag作为标杆&#xff0c;作为开启告警的开关。 3.2 低湿度告警 创建一个Flag作为标杆&#xff0c;作为开启告警的开关。 4、部件仪表 4.1 Entities table 部件预览&#xff1a; 标题样式&#xff1a; {"…

nuxt3项目服务端bulid后在本地浏览的3种方式(nuxi preview、Node.js Server、PM2)

你也许会问有了开发调试本地浏览&#xff0c;为什么还要服务端构建之后在本地浏览&#xff1f; 举个简单例子 在 Nuxt 3 服务端打包中&#xff0c;由于运行环境不同&#xff0c;无法直接访问 process 对象。服务端打包通常是在 Node.js 环境中进行的&#xff0c;而 process 对象…

Linux 手动部署JDK21 环境

1、下载包&#xff08;我下载的是tar) https://www.oracle.com/cn/java/technologies/downloads/#java21 完成后进行上传 2、检查已有JDK&#xff0c;并删除&#xff08;我原有是jdk8&#xff09; rpm -qa | grep -i java | xargs -n1 rpm -e --nodeps3、清理掉 profile中的j…

vue3 安装-使用之第一篇

首先需要node版本高于V16.14.1 安装 执行 npm create vitelatest 具体选择按照自己实际需要的来 Project name:项目名称 Select a framework:选择用哪种框架 &#xff08;我选择vue&#xff09; Select a variant: 选择用JS还是TS&#xff08;我选择JS&#xff09;找到项目&…
最新文章