code: func (e *RadixHashJoinExec) preAlloc4InnerParts() (err error) {
  	var hasNull bool
  	keyBuf := make([]byte, 0, 64)
  	for chkIdx, chkNum := 0, e.innerResult.NumChunks(); chkIdx < chkNum; chkIdx++ {
  		chk := e.innerResult.GetChunk(chkIdx)
  		partPtrs := make([]partRowPtr, chk.NumRows())
  		for rowIdx := 0; rowIdx < chk.NumRows(); rowIdx++ {
  			row := chk.GetRow(rowIdx)
  			hasNull, keyBuf, err = e.getJoinKeyFromChkRow(false, row, keyBuf)
  			if err != nil {
  				return err
  			}
  			if hasNull {
  				partPtrs[rowIdx] = partPtr4NullKey
  				continue
  			}
  			joinHash := murmur3.Sum32(keyBuf)
  			partIdx := e.radixBits & joinHash
  			partPtrs[rowIdx].partitionIdx = partIdx
  			partPtrs[rowIdx].rowIdx = e.getPartition(partIdx).PreAlloc(row)
  		}
  		e.innerRowPrts = append(e.innerRowPrts, partPtrs)
  	}
  	if e.numNonEmptyPart < len(e.innerParts) {
  		numTotalPart := len(e.innerParts)
  		numEmptyPart := numTotalPart - e.numNonEmptyPart
  		logutil.Logger(context.Background()).Debug("empty partition in radix hash join", zap.Uint64("txnStartTS", e.ctx.GetSessionVars().TxnCtx.StartTS),
  			zap.Int("numEmptyParts", numEmptyPart), zap.Int("numTotalParts", numTotalPart),
  			zap.Float64("emptyRatio", float64(numEmptyPart)/float64(numTotalPart)))
  	}
  	return
  }
docs: // preAlloc4InnerParts evaluates partRowPtr and pre-alloc the memory space
  // for every inner row to help re-order the inner relation.
  // TODO: we need to evaluate the skewness for the partitions size, if the
  // skewness exceeds a threshold, we do not use partition phase.