当前位置: 首页 > 编程日记 > 正文

关于 Rocksdb 性能分析 需要知道的一些“小技巧“ -- perf_context的“内功” ,systemtap、perf、 ftrace的颜值

文章目录

      • 内部工具
        • 包含头文件
        • 接口使用
        • 核心指标
          • Perf Context
          • IOStats Context
      • 外部工具
        • Systemtap 工具
        • Perf工具
        • Ftrace 工具

2020.8.20 23:23 ,又到了夜深人静学习时,不断得思考总结总会让繁忙一天的大脑得到舒缓。

作为单机存储引擎,Rocksdb总会被嵌入到各个存储系统之中作为核心数据的存储,那么有理有据得“甩锅”便需要一些手段。在业务场景未达到rocksdb自身性能情况下,如何将rocksdb性能在业务中的体现合理展现给使用者,让他们心服口服得"背锅"。

本篇通过内部工具 + 外部工具 的介绍 来全面展示rocksdb 整个IO链(这个IO的范围是从rocksdb入,到文件系统write系统调用完成)上的性能获取,从而更好得决定自己是否可以潇洒"甩锅"。

内部工具

facebook顶尖工程师的不断投入,精心雕琢得社区已经让rocksdb的各个核心特性及其实现都完整展现给使用者,那么一些profling的状态也必然存在。

基本的profiling使用方式如下:

包含头文件

当然这两种头文件是不同的profling状态
iostats_context.h主要是io层面的耗时统计,比如write,read等系统调用的耗时,计数
perf_context.h 主要是内部各个子流程的耗时统计,比如写wal的耗时/请求计数,写memtable的耗时/请求计数

#include “rocksdb/iostats_context.h”
#include “rocksdb/perf_context.h”

接口使用

rocksdb::SetPerfLevel(rocksdb::PerfLevel::kEnableTimeExceptForMutex); //开启profilingrocksdb::get_perf_context()->Reset(); // 初始化perf_context对象
rocksdb::get_iostats_context()->Reset() // 初始化 iostats_context对象// ...... 调用Get/Put ,或者一些其他的IO流程rocksdb::SetPerfLevel(rocksdb::PerfLevel::kDisable); // 关闭profling//获取具体的profling结果
std::cout << rocksdb::get_perf_context()->ToString() << std::endl; //获取所有的perf 状态
std::cout << rocksdb::get_iostats_context()->ToString() << std::endl; //获取所有的iostats状态
std::cout << "get_from_memtable_time: " << rocksdb::get_perf_context()->get_from_memtable_time << "write_nanos: "<< rocksdb::get_iostats_context()->write_nanos<< std::endl; // 获取某一个具体状态的数值

简单说一下rocksdb提供的perf级别,在文件perf_level.h

enum PerfLevel : unsigned char {kUninitialized = 0,             //  什么也不监控,一般不实用这个选项kDisable = 1,                   //  关闭profling功能kEnableCount = 2,               //  仅开启count计数的profling 功能kEnableTimeExceptForMutex = 3,  //  仅开启time profiling功能,我们耗时方面分析就直接开启这个级别。//  不过使用者需要注意这里统计的耗时在不同的系统上是有差异的。kEnableTimeAndCPUTimeExceptForMutex = 4, // 仅开启cpu 耗时的统计kEnableTime = 5,  // 开启所有stats的统计,包括耗时和计数 kOutOfBounds = 6  //  这个不太理解。。。。。。。反正也用不到
};

一般耗时的分析直接用kEnableTimeExceptForMutex 这个级别,如果想要抓取所有的stats信息,包括耗时和计数,就可以使用kEnableTime功能。

详细的实现主要是在perf_context_imp.h 通过宏定义来 实现一些计数和统计的接口,也是为了减少本身统计过程中函数调用的开销。

核心指标

Perf Context

Ps: 以下的耗时统计都是取决于自己什么时候调用SetPerfLevel(rocksdb::PerfLevel::kDisable);的接口,来终止prifling。

二分查找的耗时

  • user_key_comparison_count 统计二分查找的次数,如果次数过多,可能是我们配置的comparator不是很合理。当然这个也与系统中数据量的大小,是否是冷热数据有关。

block cache或者 page cache的效率

  • block_cache_hit_count 我们从block cache中读取数据的次数
  • block_read_count 从page cache中读取数据的次数,通过和上一个指标的对比来评估block cache的miss rate,从而确定当前配置下的block cache性能。(实现上,block cache是在page cache之上的一层缓存,默认是LRU)

Get 链路的耗时统计
一般以get 开头的指标,如下是比较重要那的几个

  • get_from_memtable_time 从memtable中读取数据的耗时
  • get_from_output_files_time 从sst文件中读取数据的耗时
  • seek_on_memtable_time 查找memtable的耗时

Put 链路耗时统计
一般以 write 开头的指标,如下是几个比较重要的

  • write_wal_time 写wal的耗时
  • write_memtable_time 写memtable的耗时
  • write_pre_and_post_process_time 主要是写入数据之前的一些准备耗时,不包括wal以及memtale的写入耗时
    比如在组提交过程中,非leader的写入需要等待leader完成wal的写入之后才能开始写memtble,这一些耗时也会被计算在内
    如下代码,在开始写memtale的时候才会停止计时,如果writer是非leader,则writer的状态并不是能够写memtable的,不会进入到这个逻辑,那么非leader就会等待一段时间。
    在这里插入图片描述
    之后还会进入ProcessWrite函数来统计即将写入前的write delay 部分的耗时
    在这里插入图片描述
IOStats Context

如下几个重要的耗时指标,统计的总时间取决于什么时候关闭profiling接口,也可以每一个请求都统计一次。

  • write_nanos 调用write 和 pwrite系统调用的耗时
  • read_nanos 调用read和 pread系统调用的耗时统计
  • fsync_nanos 调用fsync系统调用的耗时
  • cpu_write_nanos 官方给的描述是 : cpu在write 和 pwrite的耗时
    这里应该是统计cpu的写入key-value到文件的计算耗时,因为看代码是在compaction的最终由cpu处理 ProcessKeyValueCompaction函数的起始和末尾计算了一下耗时
  • cpu_read_nanos cpu在read 和 pread的耗时
    同样read也是在上文中的函数中进行统计的,因为ProcessKeyValueCompaction的处理过程中会涉及key-value 从底层sst文件中的读取

一个简单的demo之前的统计信息:

	.......rocksdb::get_perf_context()->Reset();rocksdb::get_iostats_context()->Reset();std::vector<string> keys, values;rocksdb::WriteOptions write_option;rocksdb::Status s;/*执行具体IO操作,stats的统计是两次put,一个get的总和*/s = binlog_vec[n_db]->Put(write_option, k, rand_value);assert(s.ok());s = db_vec[n_db]->Get(rocksdb::ReadOptions(), k, &value); assert(s.ok());s = db_vec[n_db]->Put(write_option, k, rand_value);assert(s.ok());req_num ++; buff_num ++; if (!s.ok()){   cerr << "Put failed: " << s.ToString() << endl;exit(1);}   //if ( thread_id==21 && (now() - ts) >= 1.00 )if ( (now() - ts) >= 1.00 ) //每隔一秒打印一次{   time_t temp;temp = time(NULL); printf("time is :%s thread_id %ld db%d :  count=%ld, speed=%ld\n", \ctime(&temp),thread_id, n_db, req_num, buff_num);ts = now();buff_num = 0;g_time += 10; // 关闭profilingrocksdb::SetPerfLevel(rocksdb::PerfLevel::kDisable);std::cout << "get_perf_context: \n get_from_memtable_time: " << rocksdb::get_perf_context()->get_from_memtable_time<< "\nget_from_output_files_time: " << rocksdb::get_perf_context()->get_from_output_files_time << "\nblock_read_time: " << rocksdb::get_perf_context()->block_read_time << "\nseek_on_memtable_time "<< rocksdb::get_perf_context()->seek_on_memtable_time << "\nseek_min_heap_time "<< rocksdb::get_perf_context()->seek_min_heap_time << "\neek_max_heap_time "<< rocksdb::get_perf_context()->seek_max_heap_time << "\nseek_internal_seek_time "<< rocksdb::get_perf_context()->seek_internal_seek_time << "\nwrite_wal_time "<< rocksdb::get_perf_context()->write_wal_time << "\nwrite_memtable_time "<< rocksdb::get_perf_context()->write_memtable_time << "\nwrite_delay_time "<< rocksdb::get_perf_context()->write_delay_time << "\nwrite_scheduling_flushes_compactions_time "<< rocksdb::get_perf_context()->write_scheduling_flushes_compactions_time << "\n write_pre_and_post_process_time "<< rocksdb::get_perf_context()->write_pre_and_post_process_time << "\nwrite_nanos "<< rocksdb::get_iostats_context()-> write_nanos<< "\nread_nanos "<< rocksdb::get_iostats_context()-> read_nanos<< std::endl;std::string out;db_vec[n_db]->GetProperty("rocksdb.estimate-pending-compaction-bytes", &out);fprintf(stdout, "rocksdb.estimate-pending-compaction-bytes : %s\n", out.c_str());if(g_time == 60) {std::cout << "begin write" << std::endl;judge_read = false;}   } ......

输出如下,以下的耗时统计单位都是微妙:

get_perf_context: get_from_memtable_time: 838
get_from_output_files_time: 0
block_read_time: 0
seek_on_memtable_time 0
seek_min_heap_time 0
eek_max_heap_time 0
seek_internal_seek_time 0
write_wal_time 5947
write_memtable_time 2050
write_delay_time 0
write_scheduling_flushes_compactions_time 261write_pre_and_post_process_time 899
write_nanos 4513
read_nanos 0

这样,我们就可以通过简单的rocksdb内部已有的工具来进行引擎层的profiling过程排查分析,比如上层存储系统调用rocksdb接口,我们可以将我们rocksdb内部耗时完整展示出来,那么是不是我们的问题就一目了然了。

当然这样的调试过程还会有一些麻烦,我们需要侵入业务的代码,增加一些状态统计,不过结果是精确的,即使因为统计本事的耗时所产生的误差也基本都是us级的,并不影响宏观上的性能比对。

外部工具

结合内部调试工具,我们再通过外部工具进行一些rocksdb流程上耗时的抓取,这里需要对rocksdb内部实现有一定的了解, 我们需要知道抓取一些rocksdb的IO链上的函数。

抓取之前需要应用的二进制文件中包含rocksdb的符号表,即编译rocksdb需要加入-g或者-gd b参数来编译。

大体思路上,还是说先集中在rocksdb内部的耗时之上,因为我们需要明确rocksdb自己的性能上限,处理一个key的过程中,内部各个字阶段的耗时大概是什么样子的量级,相关的测试都是基于Centos7.4 3.10内核。

Systemtap 工具

Systemtap 工具是一种可以通过脚本进行自由扩展的动态追踪技术,但是因为长时间游离于内核之外,所以在RHEL系统中是比较稳定,而其他系统则容易出现异常。

反过来说,在3.x 等旧版本内核中,systemtap 相比于eBPF 是一个巨大的优势。

首先通过systemtap 来获取我们rocksdb内部子流程上的关键函数调用栈,从而帮助大家更好的分析。

如果没有stap命令,则可以通过sudo yum install system tap -y来安装systemtap工具。

比如我们抓取写WAL 函数的调用栈,编写call_trace.stp 如下

#!/bin/stapprobe process("/home/test_binary").function("rocksdb::DBImpl::WriteToWAL")  print("------------------------------------\n")print_ubacktrace()print("------------------------------------\n")}

通过sudo stap call_trace.stp | c++filt 将每次调用WriteToWAL函数的调用栈打印出来。这里如果编译rocksdb的时候采用demangle的方式,那么就不需要c++filt了, 否则会出现一些乱码,这里使用c++filt进行过滤。

最终可以看到很多wal相关的调用栈信息如下

在这里插入图片描述

通过调用栈,我们就大概知道了从rocksdb的IO链路到上层应用链路的调用关系, 取到了这条路径上的函数,再逐层从下向上结合后面的stap脚本进行耗时统计。

以下是一个案例,可以在binary中增加多个探针,来打印对应函数的耗时情况。

!#/bin/stapglobal timesprobe process("/home/test_binary").function("rocksdb::DBImpl::WriteImpl").return,process("/home/test_binary").function("rocksdb::DBImpl::WriteToWAL").return,process("/home/test_binary").function("rocksdb::WriteBatchInternal::InsertInto").return,process("/home/test_binary").function("rocksdb::WriteBatchInternal::Iterate").return,process("/home/test_binary").function("rocksdb::MemTable::Add").return {times[pid(), ppfunc()] += gettimeofday_us() - @entry(gettimeofday_us()) #耗时及耗时信息放在times 数组之中
}probe timer.s(10) { #每隔十秒打印一次println("========%s", execname())foreach([pid, pp] in times - limit 10) {printf("pid:%5d %50s %10ld(us)\n", pid, pp, times[pid, pp])}delete times
}

最终结果如下(这个结果显然偏高了):

========%sswapper/42
pid:98097                         rocksdb::DBImpl::WriteImpl    1510686(us)
pid:98097                        rocksdb::DBImpl::WriteToWAL    1153604(us)
pid:98097            rocksdb::WriteBatchInternal::InsertInto     574674(us)
pid:98097               rocksdb::WriteBatchInternal::Iterate     437807(us)
pid:98097                             rocksdb::MemTable::Add     257805(us)

一般不建议使用这种多个探针方式进行探测,这样会对应用程序性能有比较大的影响,systemtap的执行方式是 先转换成C代码,编译成内核模块,加载到内核中,对指定的用户程序添加探针,根据指定的行为做对应的返回。如果同时有过多的探针,那肯定会对性能有比较大的影响。

所以这里抓取 的 耗时能够和rocksdb内部统计的耗时数据核对上之后(比如writeToWAL函数的消耗),再进行逐层向上抓取,当然也可以向下抓取。

比如writeToWAL之下会调用AddRecord函数进行log文件的写入,再之下会通过Flush函数进行数据的写入,通过PosixWritableFile::Append函数 调用 PosixWrite函数,最终执行到文件系统的write系统调用之上。详细的写WAL的实现可以参考Rocksdb Wal机制 底层探索。

System tap 这个工具本身还是有很多可以研究的地方,能够极大得节省内核的调试效率(本身的执行方式就是编译成对应的内核模块,加载到系统中执行的),但是在调试用户态应用过程中除了会对应用本身性能有影响之外,其他功能方面的影响还好。

Perf工具

Perf 同样是google开发出来的可以调试用户态以及内核态应用的工具,这里还是挑一些简单的子工具来用作我们rocksdb层面的性能分析。

首先Perf 能够抓取On CPU的进程消耗调用栈,且提供一个火焰图来展示调用栈的信息。

下载FlameGraph到服务器之上,进入FlameGraph目录之后通过root用户执行如下脚本抓取对应进程的On CPU消耗,并且是调用栈的形式。

#!/bin/bashpid=$1if [ -z "$pid" ];thenperf record -F 99 -g -- sleep 180 
elseperf record -F 99 -p $pid -g -- sleep 180 
fiperf script > out.perf./stackcollapse-perf.pl out.perf > out.folded
./flamegraph.pl out.folded > kernel-"$pid".svg

传入进程PID,即可生成一个可视化的.svg文件,包含on cpu的进程内部各个函数的消耗情况。
在这里插入图片描述

当然这个只能看到一个大体的百分比,我们想要看到具体的耗时情况需要切换一下子工具。

使用perf probe来增加类似于systemtap的探针功能,不过perf的采样更加轻量级,关于内核态的调试这里也是类似的,可以提前perf list来查看 可调试的探针。

  • perf probe增加探针
    这里需要提前说明一下,因为perf probe向用户态应用增加探针时可能因为编译选项的一些问题(C++工程没有demangle),则无法找到对应探测的函数地址。建议先手动找一下函数地址,直接使用函数地址进行探测。
    通过objdump工具查看函数所处二进制文件中的偏移地址,位于打印出来的第一列

    objdump /home/test_binary --syms | c++filt | grep -i "rocksdb::rocksdb::log::Writer::AddRecord"

    增加perf 探针

    sudo perf probe -x /home/test_binary '0x0000000000f7d59c'
    

    增加成功之后会给一个类似于这样的地址 probe_test_binary:abs_f7d59c,直接复制进行接下来的采样即可。
    如果是探测内核函数,更换一下命令选项即可。

    $ perf probe --add do_sys_open
    Added new event:probe:do_sys_open    (on do_sys_open)
    You can now use it in all perf tools, such as:
    perf record -e probe:do_sys_open -aR sleep 1
    
  • perf record进行采样

    sudo perf record -e probe_test_binary:abs_f7d59c -aR sleep 60

  • perf script生成可读性报告,查看采样结果

    sudo perf script
    当然这里调试内核的时候可以增加一些参数选项:

    $ perf probe -V do_sys_openAvailable variables at do_sys_open@<do_sys_open+0>char* filenameint dfdint flagsstruct open_flags opumode_t mode
    

    从而能够使用带参数的探测选项来完成更加详细的探测信息展示:

    perf probe --add 'do_sys_open filename:string'

  • perf brobe --del 探针用完之后需要删除掉

    sudo perf probe --del probe_test_binary:abs_f7d59c

    这里的perf probe还是追踪一些调用关系的逻辑,在火焰图的分析中可以再关注rocksdb层面在当前进程中的消耗占比,大体是能够看出我们rocksdb在当前CPU下的一个压力情况。

    不过很多情况,我们还是想要更加精确得了解到系统硬件以及一些系统调用执行到情况,这个时候就需要探测一些硬件相关到事件,比如cpu cache-misses,context-switches,cpu-migrations 等CPU相关的事件,这一些数据的升高,可能系统存在大量的无效线程切换,从而导致整个CPU消耗在非IO链路之上。

    或者说我们想追踪某一个内核函数的执行情况,也可以通过perf 的tracepoints进行追踪。
    接下来简单演示一下这个perf 组合命令的使用详情:

  • perf list查看可追踪的事件
    在这里插入图片描述
    或者通过perf list的子命令来查看具体的可采样的事件

    • perf list hw 查看可以采样的具体硬件事件,像cpu 的cache-misses,branch-misses,ref-cycle等重要指标

      简单说一下CPU cache, 它是操作系统设计的局部性原理的体现,利用CPU L1-cache(访问速度远高于内存,但是容量小)来保存近期CPU处理过的数据,CPU再次进行计算时,需要重新加载参与计算的数据,此时会先从L1-cache中查找,如果找到了就不去内存中找了。这样的一个优化在有大量局部性特性的数据处理过程中会极大得提升处理效率。

      如下简单的代码

      #include <stdio.h>
      #include <unistd.h>int a[10000][10000];int main(int argc, char **argv)
      {int i,j;printf("%d \n",argc);if(argc == 1){for(i = 0; i < 10000; ++i){for(j = 0; j < 10000; ++j){a[i][j] = 0;}}}else{for(i = 0; i < 10000; ++i){for(j = 0; j < 10000; ++j){a[j][i] = 0;}}}return 0;
      }
      

      这里两种相同功能,但不同赋值顺序的循环,CPU处理性能差异还是比较大的。
      第二个循环性能会比较差,因为第二个循环的j 数据每次都会变化,j控制的是行的访问,每次赋值都需要重新加载一整行的数据到CPU cache之中,所以这样的循环下CPU cache的局部性优化就不怎么明显了,而且存在大量的cache-misses

      性能差异:
      可以看到在相同环境下见到操作一亿条数据时的执行效率有两倍的差异
      在这里插入图片描述

      通过perf 验证如下:
      对应的cpu cache-misses也有接近七倍的差异,在CPU cache这里的空间局部性非常差,性能自然就会差。相当于CPU 每次加载不到cpu-cache的时候就需要访存,自然带来更大的开销。
      那就会有人问,为什么不把cpu cache再增大一点呢,这样不就有更多的空间存放更多的数据来靠近CPU执行了。

      CPU的设计工艺上 就是核心芯片,无数的功能集中在数平方厘米的地盘(计算,存储,肯定是以计算为主),为了一增大一部分的存储的性能,而让计算变得更加拥挤,自然是得不偿失。
      在这里插入图片描述

  • perf stat 实时进行events的采样
    以上案例展示了通过perf stat来 抓取具体的事件执行情况,我们也可以抓取具体进程的某个事件指标
    perf stat -e $events -p $pid sleep $time 抓取一段时时间内指定进程的指定events情况。
    这里的time单位是s
    详细的events还包括具体内核模块的函数,可以通过perf list tracepoint查看
    在这里插入图片描述

  • perf record 对给定的evets采样一段时间,做一个数据记录
    perf record -e $events -p $pid -o $output_filename sleep $time
    如果没有指定-o 参数,采样完成后会生成一个perf.data文件,否则会将针对events的采样数据存放在当前目录下自己指定的文件之中
    在这里插入图片描述

  • perf reportrecord记录的数据生成可读性的报告
    perf report -i $input_file 通过 -i 参数指定自己record生成的数据文件,如果不用-i参数,则默认会加载 perf.data数据
    接下来看到的report中的数据就类似perf top中的每个函数的消耗占用情况

Ftrace 工具

ftrace 工具通过扩展支持了各种事件的跟踪功能,来以普通文件的形式,向用户提供抓取内核系统调用的接口。
主要是通过类似于procfsdebugfs进行文件访问 。
这样 不需要额外的工具,只需要挂载/sys/kernel/debug/tracing目录,对内部的文件进行读写,来跟ftrace进行交互。

  • 一般交互是需要进入/sys/kernel/debug/tracing目录,所以第一步 root用户 执行cd /sys/kernel/debug/tracing
  • 如果该目录不存在,则用进行挂载 mount -t debugfs nodev /sys/kernel/debug
  • 设置追踪函数 echo SyS_write > set_graph_function
    通过cat available_filter_functions 能够看到当前可以追踪的内核函数,有大量的不同模块的内核函数以及系统调用
    通过cat available_events 可以看到支持追踪的事件,这个事件是内核源码中事先定义好的追踪点
  • 配置追踪选项,echo function_graph > current_tracer
    其中查看支持的追踪器可以通过cat available_tracers
    # cat available_tracers
    hwlat blk function_graph wakeup_dl wakeup_rt wakeup function nop
    
    这其中,function 表示跟踪函数的执行,function_graph 则是跟踪函数的调用关系,也就是生 成直观的调用关系图,这便是最常用的两种跟踪器。
  • 配置追踪进程选项,echo funcgraph-proc > trace_options
  • 开启追踪
    echo 1 > tracing_on
  • 关闭追踪
    echo 0 > tracing_on
  • 查看追踪结果 cat trace
    可以看到SyS_write 整体执行到底层的调用链,甚至将每一个函数的耗时都展示出来了
    在这里插入图片描述
    以上的输出含义如下:
    • 第一列表示运行的 CPU
    • 第二列是任务名称和进程 PID或者主线程ID
    • 第三列是函数执行延迟,单位是 us
    • 最后一列,则是函数调用关系图。

可以看到以上执行的整个过程还是比较复杂的,需要操作很多的文件,所以这里ftrace开发者提供了trace-cmd工具进行追踪步骤的简化。

通过yum install trace-cmd -y即可安装。
使用方式:

#追踪系统所有执行`SyS_write`  系统调用的进程
trace-cmd record -p function_graph -g SyS_write -O funcgraph-proc
trace-cmd start # 开启追踪
trace-cmd stop # 结束追踪
trace-cmd reset # 重置所有配置信息

其他详细的使用可以参考trace-cmd -h

在这里插入图片描述

这里有一个性能文件需要提前说明一下,因为ftrace 追踪的是内核的函数,采样的频率很高,实际的内核函数的执行耗时大概只有ftrace抓取的十分之一,不过并不影响我们来确认具体的执行逻辑和耗时比对(相同环境下)。

通过如上的内部工具 + 外部工具基本能够观察到整个rocksdb 引擎层的耗时情况,这个时候即使不能甩锅,也能轻松定位到具体耗时的函数,来让我们的问题分析排查过程更加精确简单。

相关文章:

一维数组求平均值c语言编程软件,c语言编程:用数组名作函数参数,编写一个对一维数组求平均值的函数,并在主函数中调用它...

#includeincludeint main(){void sort1(char*p1);void print(char*p2);static char*name[]{"zhangwww.book1234.com防采集请勿采集本网。#include #include #include float b(float arr[],int n); //<<<不知道你说的第2&#xff0c;4&#xff0c;5语句对应的是什…

2014年10月18日

我姐一个一点追求都没有弄的我气死了.女人管不住自己的臭嘴就让人烦死/ 还能不能嫁出去 蠢 女人说一个男的没追求没出息就是找枪口撞 蠢死转载于:https://www.cnblogs.com/wangduqiang/p/4180892.html

接口响应慢?那是你没用 CompletableFuture 来优化!

大多数程序员在平时工作中,都是增删改查。这里我跟大家讲解如何利用CompletableFuture优化项目代码,使项目性能更佳!

SQL Server 2012入门T-SQL基础篇:(8)Delete语句

基本的语法格式如下:Deleteform表名[where条件语句]此语句将删除表的部分或者全部记录;(1)带WHERE条件子句,将删除符合条件的记录:可以看到已经删除了"EmployeeKey1"的记录;(2)不带条件的delete的语句,将表中删除所有记录;转载于:https://blog.51cto.com/281816327/1…

30张图带你彻底理解红黑树

当在10亿数据进行不到30次比较就能查找到目标时,不禁感叹编程之魅力!人类之伟大呀!—— 学红黑树有感。终于,在学习了几天的红黑树相关的知识后,我想把我所学所想和所感分享给大家。红黑树是一种比较难的数据结构,要完全搞懂非常耗时耗力,红黑树怎么自平衡?什么时候需要左旋或右旋?插入和删除破坏了树的平衡后怎么处理?等等一连串的问题在学习前困扰着我。如果你在学习过程中也会存在我的疑问,那么本文对你会有帮助,本文帮助你全面、彻底地理解红黑树!

Linux内核分析--理解进程调度时机、跟踪分析进程调度和进程切换的过程

学号后三位:426 原创作品转载请注明出处 https://github.com/mengning/linuxkernel/ 1.进程的创建 除了0号进程&#xff08;系统创建的&#xff09;之外&#xff0c;linux系统中都是由其他进程创建的。创建新进程的进程&#xff0c;即调用fork函数的进程为父进程&#xff0c;…

数据结构 -- 散列表

散列表作为一种能够提供高效插入&#xff0c;查找&#xff0c;删除 以及遍历的数据结构&#xff0c;被应用在很多不同的存储组件之中。 就像rocksdb中的hashskiplist&#xff0c;redis的有序集合&#xff0c;java的 LinkedHashMap 等 都是一些非常有特色的核心数据结构&#xf…

c语言编程题餐饮服务打分,求详细分析C语言题餐饮服务质量调查打分题和答案..._质量员考试_帮考网...

bangsaizhuo新兵答主11-09TA获得超过6761个赞二、填空题1. &#xff3f;&#xff3f;&#xff3f;变量&#xff3f;&#xff3f;是指在程序运行过程中&#xff0c;值可以发生变化的量。2.C语言是一种&#xff3f;&#xff3f;&#xff3f;&#xff3f;区分&#xff3f;(区分/不…

为什么阿里巴巴修正了HashMap关于1024个元素扩容的次数?(典藏版)

此番修正主要是每个人对「扩容」定义存在了分歧,在JDK1.8中如果没有给HashMap设置初始容量,那么在第一次put()操作的时候会进行resize()。而有的人认为这算一次扩容,有的人认为这不是一次扩容,这只是HashMap容量的初始化。所以存储1024的元素时:前者的人认为扩容次数为8次。后者的人认为扩容次数为7次。孤尽老师说对此分歧,希望用没有「二义性」的语言来表示,所以「扩容次数」修正为「resize次数」。

【转】每天一个linux命令(31): /etc/group文件详解

原文网址&#xff1a;http://www.cnblogs.com/peida/archive/2012/12/05/2802419.html Linux /etc/group文件与/etc/passwd和/etc/shadow文件都是有关于系统管理员对用户和用户组管理时相关的文件。linux /etc/group文件是有关于系统管理员对用户和用户组管理的文件,linux用户组…

C#设计模式(7)——适配器模式(Adapter Pattern)

一、引言在实际的开发过程中&#xff0c;由于应用环境的变化&#xff08;例如使用语言的变化&#xff09;&#xff0c;我们需要的实现在新的环境中没有现存对象可以满足&#xff0c;但是其他环境却存在这样现存的对象。那么如果将“将现存的对象”在新的环境中进行调用呢&#…

强烈建议你不要再使用Date类了!!!

这里就不细说修改流程了,主要说一下我们在改造的时候遇到的一些问题。(Date从现在开始)是一个糟糕的类型,这解释了为什么它的大部分内容在 Java 1.1 中被弃用(但不幸的是仍在使用)。只能说这种基础的类改起来牵一发动全身,需要从DO实体类看起,然后就是各种Converter,最后是DTO。这个改造难度不高,但是复杂度非常高,一个地方没改好,轻则接口报错,重则启动失败,非常耗费精力,真不想改。我们要改的原因很简单,我们的代码缺陷扫描规则认为这是一个必须修改的缺陷,否则不给发布,不改不行,服了。

windows 安装MySQL服务 zip解压程序

1&#xff1a;配置 my.ini 文件 如下&#xff1a; [mysql] default-character-setutf8[mysqld] port3306basedirD:\\Program Files\\databases\\mysql-5.7.24datadirD:\\Program Files\\databases\\mysql-5.7.24\\datamax_connections200max_connections200character-set-serve…

数据结构 -- 图与图存储

我们在使用像QQ &#xff0c;微信&#xff0c;微博&#xff0c;快手&#xff0c;抖音等社交软件的过程中经常需要添加好友&#xff0c;关注好友和被好友关注。这个过程中 这样的社交网络中的好友关系就需要被存储下来&#xff0c;存储在各个公司的后台服务器之上&#xff0c;都…

Struts2 验证规则配置文件

1. Action级别校验命名格式&#xff1a; ActionClassName-validation.xml 2. Action中某个方法的校验命名格式&#xff1a; ActionClassName-ActionAliasName-validation.xml 注意&#xff1a;这里的ActionAliasName(action别名)指的是struts.xml中Action name"XX"的…

c语言中手机系统,一种手机课堂C语言编程系统的制作方法

技术特征&#xff1a;1.一种手机课堂C语言编程系统&#xff0c;其特征在于&#xff1a;该系统由手机端C语言编译运行单元、嵌入式主机端传输单元、台式机端显示单元和投影仪端显示单元组成&#xff1b;所述手机端C语言编译运行单元、嵌入式主机端传输单元、台式机端显示单元和投…

cpp中sizeof与指针

一直不清楚c的sizeof&#xff0c;现在通过实验得到了一些了解。 1 #include<iostream>2 3 using namespace std;4 5 class A{6 private:7 char * a1;8 // ! static int totalPeople0; //error: ISO C forbids in-class initialization of non-const static me…

利用Python制作简单的小程序:IP查看器

前言 说实话&#xff0c;查看电脑的IP&#xff0c;也挺无聊的&#xff0c;但是够简单&#xff0c;所以就从这里开始吧。IP地址在操作系统里就可以直接查看。但是除了IP地址&#xff0c;我们也想通过IP获取地理地址和网络运营商情况。IP地址和地理地址并没有固定的关系&#xff…

一文带你看透 GDB 的 实现原理 -- ptrace真香

文章目录Ptrace 的使用GDB 的基本实现原理Example1 通过ptrace 修改 被追踪进程的内存数据Example2 通过ptrace 对被追踪进程进行单步调试Ptrace的实现PTRACE_TRACEMEPTRACE_ATTACHPTRACE_CONTPTRACE_SINGLESTEPPTRACE_PEEKDATAPTRACE_POKEDATAPTRACE_GETREGSGDB本身能够attach…

线程使用 c语言,如何用C语言实现多线程

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼Windows操作系统&#xff0c;C语言实现多线程&#xff1a;#include #include DWORD APIENTRY ThreadOne ( LPVOID threadArg ){printf ( "线程开始啦&#xff0c;参数是&#xff1a;%s\n" , (char *)threadArg );return …

eclipse设置保护色非原创

eclipse操作界面默认颜色为白色。对于我们长期使用电脑编程的人来说&#xff0c;白色很刺激我们的眼睛&#xff0c;所以我经常会改变workspace的背景色&#xff0c;使眼睛舒服一些。设置方法如下&#xff1a;1、打开window->Preference,弹出Preference面板2、展开General标签…

markdown 使用

1&#xff1a;新手建议 2&#xff1a;windows下使用 http://markdownpad.com/ 3&#xff1a;linux http://benweet.github.io/stackedit/# 二&#xff1a;使用工具 mac http://moustand.com/windows http://markdownpad.com/http://wowubuntu.com/markdown/注&#xff1a;建议 …

python第九章:面向对象--小白博客

面向对象介绍 一、面向对象和面向过程 面向过程&#xff1a;核心过程二字&#xff0c;过程即解决问题的步骤&#xff0c;就是先干什么后干什么 基于该思想写程序就好比在这是一条流水线&#xff0c;是一种机械式的思维方式 优点&#xff1a;复杂的过程流程化 缺点&…

分布式一致性(共识)算法(Paxos,raft,ZAB)的一些总结

文章目录前言CAP理论C consistency 一致性A availability 可用性P partition tolerance 分区容错性一致性模型弱一致性强一致性强一致性算法需要明确的问题强一致算法&#xff1a; 主从同步强一致性算法&#xff1a;多数派强一致算法&#xff1a;PaxosBasic PaxosMulti Paxos第…

dedecms 财付通接口

用织梦做了个旅游网站&#xff0c;网址&#xff1a;http://www.redtourism.cn/ 客户要求财付通支付&#xff0c;上网找了下 不是要买就是要钱&#xff0c;只有自己写了。 代码&#xff1a; <?phpif(!defined(DEDEINC)) exit(Request Error!);/** *财付通接口类 */class ten…

r语言手动算两个C指数p值,如何用R语言进行Pvalue显著性标记?

作者&#xff1a;一只想飞的喵审稿&#xff1a;童蒙编辑&#xff1a;angelica箱线图是统计学中较常见的图形之一。这篇文章将讲述如何简单比较两组或多组的平均值&#xff0c;且添加显著性标记。通常情况根据显著性p值的数值大小&#xff0c;分为四类&#xff1a;(1)0.01≤p<…

linux yum命令详解

yum&#xff08;全称为 Yellow dog Updater, Modified&#xff09;是一个在Fedora和RedHat以及SUSE中的Shell前端软件包管理器。基於RPM包管理&#xff0c;能够从指定的服务器自动下载RPM包并且安装&#xff0c;可以自动处理依赖性关系&#xff0c;并且一次安装所有依赖的软体包…

OpenCV编译viz模块

首先需要编译vtk。注意不要使用最新的master版本&#xff0c;而是使用tag分支下的最新版本。当前最新版本是https://gitlab.kitware.com/vtk/vtk/tree/v8.2.0版本。直接点击下载源码即可。 Cmake选项设置&#xff1a; 如果需要编译成静态库&#xff0c;需要在CXX_FLAGS、C_FLAG…

vim 成“神“之路 (一)

文章目录1. 安装1.1 linux1.2 MacOs的安装1.3 Windows的安装1.4 vim中文帮助文档安装2. vim基本概念和基础命令2.1 基本的键位映射如下:2.2 vim模式2.3 vim的选项和基本配置2.3.1 备份和跨会话撤销文件2.3.2 vim中支持鼠标3. vim 常用命令 -- 应对稍复杂任务3.1 光标移动3.2 文…

android 添加头参数,Retrofit添加header参数的几种方法

(1)使用注解的方式添加一个Header参数publicinterfaceUserService {Headers("Cache-Control: max-age640000")GET("/tasks")Call> getTasks();}添加多个Header参数publicinterfaceUserService {Headers({"Accept: application/vnd.yourapi.v1.full…