精华内容
下载资源
问答
  • MemoryAnalyzer主要用于分析jvm运行过程中导致内存溢出、内存泄漏的工具,MemoryAnalyzer主要用于分析jvm运行过程中导致内存溢出、内存泄漏的工具,MemoryAnalyzer主要用于分析jvm运行过程中导致内存溢出、内存泄漏...
  • MemoryAnalyzer-1.10.0.zip

    2020-05-02 10:37:17
    MemoryAnalyzer-1.10.0 最新版本window+Linux 64位系统使用,都打包到一起了,官网下载贼慢还经常无法下载,需要的拿去。
  • MemoryAnalyzer 使用中文

    2019-07-07 11:29:20
    MemoryAnalyzer 使用中文
  • 1、MemoryAnalyzer使用说明文档/使用指南 2、MemoryAnalyzer 1.8.1下载: http://120.52.51.17/ftp.jaist.ac.jp/pub/eclipse/mat/1.8.1/MemoryAnalyzer-1.8.1.201809100846.zip
  • MAT(Memory Analyzer Tool)

    2018-12-06 09:14:12
    MAT(Memory Analyzer Tool)工具是eclipse的一个插件,使用起来非常方便,尤其是在分析大内存的dump文件时,可以非常直观的看到各个对象在堆空间中所占用的内存大小、类实例数量、对象引用关系、利用OQL对象查询,...
  • Eclipse Memory Analyzer mac 版本 1.8.1 & 安装使用指南
  • MyMemory机器自动翻译插件 不受时间限制 免费使用 还有视频教程 请在旺旺 找cyl365 免费索取 还有Trados 2017 原创教程
  • NET-Memory-Profiler 4-使用手册,检查内存,是否溢出等,记录,图片查看
  • Eclipse Memory Analyzer是一款基于Eclipse的内存分析工具,mac版,不需要安装Eclipse,可以直接运行,用来分析内存泄漏等问题
  • Memory Compiler使用方法介绍。内含使用实例,详细介绍软件使用方法,配置,及图文讲解
  • ANTS Memory Profiler 8.1 安装包+激活工具+教程,含工具
  • .NET Memory.Profiler.v4.0完美破解版,检测内存,定位未释放资源。非常好用。
  • MAT Eclipse Memory Analyzer 中文文档 PDF 共 93 页 MAT Eclipse Memory Analyzer 中文文档 PDF 共 93 页
  • SDL Trados MyMemory插件

    2016-05-03 09:25:34
    MyMemory云记忆库/机器自动翻译插件(远程在线记忆库+类似Google和微软的机器翻译功能),全部免费使用。用于Trados 2015/SR1/SR2。
  • MemoryAnalyzer

    热门讨论 2014-05-21 14:24:28
    分析dump文件,直接解压点击MemoryAnalyzer.exe就可以使用。
  • mat独立版Memory Analyzer Tool mac版 mat独立版Memory Analyzer Tool mac版
  • memory analyzer 内存泄露 MAC版本MemoryAnalyzer-1.7.0.20170613-macosx.cocoa.x86_64.zip
  • Memory Analyzer tool(MAT) 独立工具非eclipse继承插件 超好用
  • Memory Systems: Cache, DRAM, Disk shows you how to resolve this problem. The book tells you everything you need to know about the logical design and operation, physical design and operation, ...
  • 进程间通信之共享内存 shared memory ) 1 效率最高 2 存在竞态 七种进程间通信方式: 一 无名管道( pipe ) 二 有名管道( fifo ) 三 共享内存 shared memory 四 信号 sinal 五 消息队列 message queue ) ...
  • 内存优化分析工具,使用离线激活模式,亲测可用,永久有效!
  • Shared Memory

    千次阅读 2018-04-16 13:42:59
    1、引言 在global memory部分,数据对齐和连续是提升性能的很重要的因素,当使用L1 cache的时候,对齐问题不再是问题,但是非连续的获取内存依然会降低性能。依赖于算法本质,某些情况下,非连续访问是不可避免的。...

    1、引言

    在global memory部分,数据对齐和连续是提升性能的很重要的因素,当使用L1 cache的时候,对齐问题不再是问题,但是非连续的获取内存依然会降低性能。依赖于算法本质,某些情况下,非连续访问是不可避免的。使用shared memory是另一种提高性能的方式。

    2、Introduction CUDA Shared Memory

    GPU上的memory有两种:

    1、On-board memory

    2、On-chip memory

    global memory就是一块很大的on-board memory,并且有很高的latency;而shared memory正好相反,是一块很小、低延迟的on-chip memory,比global memory拥有高得多的带宽。我们可以把他当做可编程的cache,其主要作用有:

    1、An intra-block thread communication channel   一个block中线程间交流通道

    2、A program-managed cache for global memory data  可编程的cache

    3、Scratch pad memory for transforming data to improve global memory access patterns 

    shared memory(SMEM)是GPU的重要组成之一。物理上,每个SM包含一个当前正在执行的block中所有thread共享的低延迟的内存池。SMEM使得同一个block中的thread能够相互合作,重用on-chip数据,并且能够显著减少kernel需要的global memory带宽。由于CUDA可以直接显式的操作SMEM的内容,所以又被称为可编程缓存。
    由于shared memory和L1要比L2和global memory更接近SM,shared memory的延迟比global memory低20到30倍,带宽大约高10倍。
    CUDA性能优化----Shared Memory - 樂不思蜀 - 樂不思蜀
    当一个block开始执行时,GPU会分配其一定数量的shared memory,这个shared memory的地址空间会由block中的所有thread 共享。shared memory是划分给SM中驻留的所有block的,也是GPU的稀缺资源。所以,使用越多的shared memory,能够并行的active thread blocks就越少。
    关于Program-Managed Cache:在C语言编程里,循环(loop transformation)一般都使用cache来优化。在循环遍历的时候使用重新排列的迭代顺序可以很好利用cache局部性。在算法层面上,我们需要手动调节循环来达到令人满意的空间局部性,同时还要考虑cache size。cache对于程序员来说是透明的,编译器会处理所有的数据移动,我们没有能力控制cache的行为。shared memory则是一个可编程可操作的cache,程序员可以完全控制其行为。

    Shared Memory Allocation

    我们可以动态或者静态的分配shared memory,其声明即可以在kernel内部也可以作为全局变量。CUDA支持声明1D、2D和3D的shared memory数组。其标识符为: __shared__
    静态声明2D浮点型数组:
    
     

    __shared__ float tile[size_y][size_x];

    如果在kernel中声明的话,其作用域就是kernel内,否则是对所有kernel有效。如果shared memory的大小在编译期未知的话,可以使用 extern关键字修饰,例如下面声明一个未知大小的1D数组:
    
     

    extern __shared__ int tile[];

    由于其大小在编译期未知,我们需要在每个kernel调用时,动态的分配其shared memory,也就是最开始提及的第三个参数:
    
     

    kernel<<<grid, block, isize * sizeof(int)>>>(...)

    注意: 只有1D数组才能这样动态使用。

    Shared Memory Banks and Access Mode

    当优化内存性能时,有两个重要的因素来量化:latency和bandwidth。shared memory能够用来隐藏由于latency和bandwidth对性能的影响。下面将解释shared memory的组织方式,以便研究其对性能的影响。
    (1) Memory Banks
    为了获得高带宽,shared memory被分成32( 计算能力1.x的device划分为16个banks)个相等大小的内存块,每块大小32-bit(4 bytes),他们可以被同时访问。不同的计算能力的device,shared memory以不同的模式映射到不同的块(稍后详解)。如果warp访问shared memory,对于每个bank只访问不多于一个内存地址,那么只需要一次内存传输就可以了,否则需要多次传输,因此会降低内存带宽的使用。
    (2) Banks Conflict
    当一个warp中多个地址请求落在同一个bank中就会发生bank conflict,从而导致请求多次执行。硬件会把这类请求分散到尽可能多的没有conflict的那些传输操作里面,降低有效带宽的因素是被分散到的传输操作个数。 warp有三种典型的获取shared memory的模式:

    · Parallel access:多个地址分散在多个bank。

    · Serial access:多个地址落在同一个bank。

    · Broadcast access:一个地址读操作落在一个bank。

    Parallel access是最通常的模式,这个模式表示,一些(也可能是全部)地址请求能够被一次传输解决。理想情况是,获取无conflict的shared memory的时,每个地址都在落在不同的bank中。
    Serial access是最坏的模式,如果warp中的32个thread都访问了同一个bank中的不同位置,那就是32次单独的请求,而不是同时访问了。
    Broadcast access也是只执行一次传输,然后传输结果会广播给所有发出请求的thread。这样的话就会导致带宽利用率低。
    下图是最优情况的访问图示,每个线程访问一个32-bit的数据,不存在bank conflict:
    CUDA性能优化----Shared Memory - 樂不思蜀 - 樂不思蜀
     下图是不规律的随机访问模式,因为每个thread访问不同的bank,因此也没有冲突:
    CUDA性能优化----Shared Memory - 樂不思蜀 - 樂不思蜀
     下图是bank冲突的情况,几个threads访问同一个bank,会产生下列两种行为:

    · Conflict-free broadcast access if threads access the same address within a bank

    · Bank conflict access if threads access different addresses within a bank

    CUDA性能优化----Shared Memory - 樂不思蜀 - 樂不思蜀
      (3) Access Mode
    根据device不同的计算能力版本,bank的大小配置也不同,具体为:

    · 4 bytes for devices of compute capability 2.x

    · 8 bytes for devices of compute capability 3.x

    以Fermi的GPU为例,它有32个banks,每个bank 32-bit,即4 bytes,每个bank的带宽是32bits每两个cycle。连续的32位数据映射到连续的bank中,也就是说,bank的索引和shared memory地址的映射关系如下:
    
     

     bank index = (byte address ÷ 4 bytes/bank) % 32 banks

    下图是Fermi的地址映射关系,注意到,bank中每个地址相差32,相邻的word分到不同的bank中以便使warp能够获得更多的并行获取内存操作(获取连续内存时,连续地址分配到了不同bank中)。
    CUDA性能优化----Shared Memory - 樂不思蜀 - 樂不思蜀
    当同一个warp的两个thread要获取同一个地址(注意是同一个地址,同一个bank会造成冲突)的时候并不发生bank conflict。对于读操作,会用一次transaction获得结果后广播给所有请求,当写操作时,只有一个thread会真正去写,但是哪个thread执行是无法确定的。
    对于Kepler设备来说,shared memory有两种地址模式的32个banks:

    · 64-bit mode

    · 32-bit mode

    在64-bit模式中,连续的64-bits字会映射到连续的bank。每个bank带宽是64bite/1个clock。其映射关系公式:
    
     

     bank index = (byte address ÷ 8 bytes/bank) % 32 banks

    这里,如果两个thread访问同一个64-bit中的任意一个sub-word(1byte)也不会导致bank conflict,因为一次64-bit(bank带宽64bit/cycle)的读操作就可以满足请求了。也就是说, 同等情况下,64-bit模式一般比32-bit模式更少碰到bank conflict。
    下图表示了32-bit模式下从字节地址到bank索引的映射关系图。上面表示用字节地址和4-byte word索引标签的共享内存,下面表示从4-byte word索引到bank索引的映射关系。尽管word 0和word 32都在bank0中,同时读这两个word也不会导致bank conflict(64-bit/cycle):
    CUDA性能优化----Shared Memory - 樂不思蜀 - 樂不思蜀
    下图是64-bit模式下,conflict-free的情况,每个thread获取不同的bank:
    CUDA性能优化----Shared Memory - 樂不思蜀 - 樂不思蜀
    下图是另一种conflict-free情况,两个thread或获取同一个bank中的word:
    CUDA性能优化----Shared Memory - 樂不思蜀 - 樂不思蜀
    下图红色箭头是三路bank conflict发生的情况:
      CUDA性能优化----Shared Memory - 樂不思蜀 - 樂不思蜀
      (3) Memory Padding
    memory padding是一种避免bank conflict的方法,如下图所示,所有的thread分别访问了bank0的5个不同的word,这时就会导致bank conflict,我们采取的方法就是在每N(bank数目)个word后面加一个word,这样就如下面右图那样,原本bank0的每个word转移到了不同的bank中,从而避免了bank conflict。
    CUDA性能优化----Shared Memory - 樂不思蜀 - 樂不思蜀
    增加的这些word不会用来存储数据,其唯一的作用就是移动原始bank中的word,避免冲突。使用memory padding会导致block可获得shared memory中有用的数量减少。内存填充后,需要重新计算数组索引以确保可以访问到正确的数据。注意Fermi和Kepler的bank宽度不同,所以针对于Fermi的填充模型用于Kepler可能导致bank conflict。
      (3) Access Mode Configuration
    对Kepler来说,默认情况是4-byte模式,可以用下面的API来查看:
    
     

     cudaError_t cudaDeviceGetSharedMemConfig(cudaSharedMemConfig *pConfig);

    返回结果放在pConfig中,其结果可以是下面两种:

    cudaSharedMemBankSizeFourByte

    cudaSharedMemBankSizeEightByte

    可以使用下面的API来设置bank的大小:
    
     

     cudaError_t cudaDeviceSetSharedMemConfig(cudaSharedMemConfig config);

    bank的配置参数如下三种:

    cudaSharedMemBankSizeDefault

    cudaSharedMemBankSizeFourByte

    cudaSharedMemBankSizeEightByte

    在启动不同的kernel之间修改bank配置会有一个隐式的device同步。 修改shared memory的bank大小不会增加shared memory的利用率或者影响kernel的Occupancy,但是对性能是一个主要的影响因素。一个大的bank会产生较高的带宽,但是鉴于不同的access pattern,可能导致更多的bank conflict。

    Configuring the Amount of Shared Memory

    每个SM拥有64 KB的片上内存,shared memory和L1 cache共享这块内存。CUDA提供了两种方式配置它们各自的大小,参考 CUDA学习----Memory Model,里面提到的是 Per-kernel configuration的情况。

    Per-device configuration

    Per-kernel configuration

    
     

    cudaError_t cudaDeviceSetCacheConfig(cudaFuncCache cacheConfig);

    对于 Per-device configuration的情况用以上API,两种情况类似,只是作用范围不同。配置方式孰优孰劣取决于kernel用的shared memory的多少。

    Synchronization

    因为shared memory可以被同一个block中的不同的thread同时访问,当同一个地址的值被多个thread修改就导致了inter-thread conflict,所以我们需要同步操作。CUDA提供了两类block内部的同步操作,即:

    · Barriers

    · Memory fences

    对于barriers,所有thread会等待其他threads到达barrier point;对于Memory fence,所有threads会被阻塞直到所有修改memory的操作对其他threads可见。下面解释下CUDA需要同步的主要原因:weakly-ordered。
    (1) Weakly-Ordered Memory Model
    现代内存架构有非常宽松的内存模式,也就是意味着,memory的获取不必按照程序中的顺序来执行。CUDA采用了一种叫做weakly-ordered内存模型来获取更激进的编译器优化。
    GPU thread写数据到不同的memory的顺序(比如shared memory,global memory,page-locked host memory或者另一个device上的memory)同样没必要跟程序里面顺序相同。一个thread的读操作的顺序对其他thread可见时也可能与实际执行写操作的thread顺序不一致。
    为了显式的强制程序以一个确切的顺序运行,就需要用到fence和barrier。它们也是唯一的方式能保证kernel与其它线程分享资源时对memory有正确行为。
    (2) Explicit Barrier
    可以在kernel中设置一个barrier point通过调用下列函数:
    
     

    void __syncthreads();

    __syncthreads就是作为一个barrier point起作用, block中的threads必须等待所有thread都到达这个point后才能继续下一步。这也保证了所有在这个point之前获取global memory和shared memory的操作对同一个block中所有thread可见。 __syncthreads被用来协作同一个block中的thread通信。当一些thread获取memory相同的地址时,就会导致潜在的问题(read-after-write,write-after-read和write-after-write)从而引起未定义行为状态,此时就可以使用__syncthreads来避免这种情况。
    使用__syncthreads要相当小心,只有在所有thread都会到达这个point时才可以调用这个同步,显而易见, 如果同一个block中的某些thread永远都不能到达该point,那么程序将一直等下去,下面代码就是一种错误的使用方式:
    
     
    if (threadID % 2 == 0)
    __syncthreads();
    else
    __syncthreads();
    如果在block之间不同步的话,thread blocks可能以任意顺序,并行或者串行,在任意的SM上被执行。如果一个CUDA kernel需要全局同步,可以通过在同步点分割kernel和启动多个kernel来达到这种期望的行为。
    (3) Memory Fence
    这种方式保证了任何在fence之前的memory写操作对fence之后thread都可见,也就是,fence之前写完了,fence之后其它thread就都知道这块memory写后的值了。fence的设置范围比较广,分为:block,grid和system。 可以通过下面的API来设置fence:
    
    

    void __threadfence_block();

    void __threadfence();

    void __threadfence_system();

    其中,第一个函数是对应的block范围的,也就是保证同一个block中thread在fence之前写完的值对block中其它的thread可见,不同于barrier,该函数不需要所有的thread都执行;第二个函数是对应grid范围的;第三个对用system的,其范围针对整个系统,包括device和host。
    (4) Volatile Qualifier
    声明一个使用global memory或者shared memory的变量,用volatile修饰符来修饰该变量的话,会组织编译器做一个该变量的cache优化。使用该修饰符后,编译器就会认为该变量可能在某一时刻被别的thread改变,如果使用cache优化的话,得到的值就缺乏时效,因此使用volatile强制每次都到global 或者shared memory中去读取其绝对有效值。

    3、Checking the Data Layout of Shared Memory

    我们在设计使用shared Memory的时候应该关注下面的信息:

    · Mapping data elements across Memory banks

    · Mapping from thread index to shared Memory offset

    搞明白这两点,就可以掌握shared memory的使用了,从而构建出高性能的代码。

    Square Shared Memory

    我们可以以一种直接的方式用shared memory缓存全局内存中的方阵。下图展示了一个每一维度有32个元素并以row-major存储在shared memory的数组,图的最上方是该矩阵实际的一维存储图示,下方是通过映射4-byte数据和banks关系的逻辑二维shared memory:
    CUDA性能优化----Shared Memory - 樂不思蜀 - 樂不思蜀
     我们可以使用下面的语句静态声明一个2D的shared memory变量:
    
     

    __shared__ int tile[N][N];

    因为是方阵,可以从2D线程块中以相邻的thread获取相邻的元素的方式访问数据:

     tile[threadIdx.y][threadIdx.x]

     tile[threadIdx.x][threadIdx.y]

    上面两种方式哪个性能更好呢?这就需要注意thread和bank的映射关系了,我们最希望看到的是同一个warp中的thread获取的是不同的bank。同一个warp中的thread可以使用连续的threadIdx.x来确定。不同bank中的元素同样是连续存储的,以word大小作为偏移。因此,最好是让连续的thread(由连续的threadIdx.x确定)获取shared memory中连续的地址, 由此得知,tile[threadIdx.y][threadIdx.x]应该展现出更好的性能以及更少的bank conflict。
    (1) Access Row-Major versus Column-Major
    假设我们的grid有2D的block(32,32),定义如下:
    
     
    #define BDIMX 32
    #define BDIMY 32
    dim3 block(BDIMX,BDIMY);
    dim3 grid(
    1,1);
    我们对这个kernel有如下两个操作:

    · 将thread索引以row-major写到2D的shared memory数组中;

    · 从shared memory中读取这些值并写入到global memory中。

    kernel代码如下:
    
     
    __global__ void setRowReadRow(int *out) {
    // declare static 2D shared memory
    __shared__ int tile[BDIMY][BDIMX];
    // 因为block只有一个
    unsigned int idx = threadIdx.y * blockDim.x + threadIdx.x;
    // shared memory store operation
    tile[threadIdx.y][threadIdx.x] = idx;
    // 这里同步是为了使下面shared memory的获取以row-major执行
    // 避免若有的线程未完成,而其他线程已经在读shared memory的情况
    __syncthreads();
    // shared memory load operation
    out[idx] = tile[threadIdx.y][threadIdx.x] ;
    }
    此段有三个内存操作:(1)向shared Memory存数据;(2)从shared Memor取数据;(3)向global Memory存数据。
    因为在同一个warp中的thread使用连续的threadIdx.x来检索title,该kernel是没有bank conflict的。如果交换上述代码threadIdx.y和threadIdx.x的位置,就变成了column-major的顺序。每个shared memory的读写都会导致Fermi上32-way的bank conflict或者在Kepler上16-way的bank conflict。
    
     
    __global__ void setColReadCol(int *out) {
    // static shared memor
    __shared__ int tile[BDIMX][BDIMY];
    // mapping from thread index to global memory index
    unsigned int idx = threadIdx.y * blockDim.x + threadIdx.x;
    // shared memory store operation
    tile[threadIdx.x][threadIdx.y] = idx;
    // wait for all threads to complete
    __syncthreads();
    // shared memory load operation
    out[idx] = tile[threadIdx.x][threadIdx.y];
    }
    编译运行结果如下(在K40上以4-byte模式运行):
    
     
    $ nvcc checkSmemSquare.cu o smemSquare
    $ nvprof .
    /smemSquare
    ./smemSquare at device 0 of Tesla K40c with Bank Mode:4-byte
    <<< grid (1,1) block (32,32)>>
    Time(
    %) Time Calls Avg Min Max Name
    13.25% 2.6880us 1 2.6880us 2.6880us 2.6880us setColReadCol(int*)
    11.36% 2.3040us 1 2.3040us 2.3040us 2.3040us setRowReadRow(int*)
    从结果可以看出,row-major的kernel表现更出色。
    然后 使用nvprof命令的下面的两个参数来衡量相应的bank-conflict:
    
     

    shared_load_transactions_per_request shared_store_transactions_per_request

    运行结果如下(K40,8-byte模式下),row-major只有一次transaction,而column-major需要16次,如果4-byte模式下,可能需要32次:
    
     
    Kernel:setColReadCol (int*)
    1 shared_load_transactions_per_request 16.000000
    1 shared_store_transactions_per_request 16.000000
    Kernel:setRowReadRow(
    int*)
    1 shared_load_transactions_per_request 1.000000
    1 shared_store_transactions_per_request 1.000000
    Writing Row
    -Major and Reading Column-Major
    (2) Writing Row-Major and Reading Column-Major
    下面代码实现以row-major写shared memory,以column-major读shared memory:
    
     
    __global__ void setRowReadCol(int *out) {
    // static shared memory
    __shared__ int tile[BDIMY][BDIMX];
    // mapping from thread index to global memory index
    unsigned int idx = threadIdx.y * blockDim.x + threadIdx.x;
    // shared memory store operation
    tile[threadIdx.y][threadIdx.x] = idx;
    // wait for all threads to complete
    __syncthreads();
    // shared memory load operation
    out[idx] = tile[threadIdx.x][threadIdx.y];
    }
    下图展示了用简单的5路bank shared memory实现两种内存操作:
    CUDA性能优化----Shared Memory - 樂不思蜀 - 樂不思蜀
     用nvprof命令查看相关bank conflict情况:
    
     
    Kernel:setRowReadCol (int*)
    1 shared_load_transactions_per_request 16.000000
    1 shared_store_transactions_per_request 1.000000
    从结果可以看出:写操作是没有conflict的,读操作则引起了一个16次的transaction。

    Dynamic Shared Memory

    正如前文所说,我们可以全局范围的动态声明shared Memory,也可以在kernel内部动态声明一个局部范围的shared Memory。注意,动态声明必须是未确定大小一维数组,因此,我们就需要重新计算索引。因为我们将要以row-major写,以colu-major读,所以就需要保持下面两个索引值:

    · row_idx:1D row-major 内存的偏移

    · col_idx:1D column-major内存偏移

    kernel代码:

    复制代码
    __global__ void setRowReadColDyn(int *out) {
        // dynamic shared memory
        extern __shared__ int tile[];
        // mapping from thread index to global memory index
        unsigned int row_idx = threadIdx.y * blockDim.x + threadIdx.x;
        unsigned int col_idx = threadIdx.x * blockDim.y + threadIdx.y;
        // shared memory store operation
        tile[row_idx] = row_idx;
        // wait for all threads to complete
        __syncthreads();
        // shared memory load operation
        out[row_idx] = tile[col_idx];
    }            
    复制代码

    kernel调用时配置的shared Memory:

    setRowReadColDyn<<<grid, block, BDIMX * BDIMY * sizeof(int)>>>(d_C);

    查看transaction:

    Kernel: setRowReadColDyn(int*)
    1 shared_load_transactions_per_request 16.000000
    1 shared_store_transactions_per_request 1.000000

    该结果和之前的例子相同,不过这里使用的是动态声明。

    Padding Statically Declared Shared Memory

    直接看kernel代码:

    复制代码
    __global__ void setRowReadColPad(int *out) {
        // static shared memory
        __shared__ int tile[BDIMY][BDIMX+IPAD];
        // mapping from thread index to global memory offset
        unsigned int idx = threadIdx.y * blockDim.x + threadIdx.x;
        // shared memory store operation
        tile[threadIdx.y][threadIdx.x] = idx;
        // wait for all threads to complete
        __syncthreads();
        // shared memory load operation
        out[idx] = tile[threadIdx.x][threadIdx.y];
    }                            
    复制代码

    改代码是setRowReadCol的翻版,查看结果:

    Kernel: setRowReadColPad(int*)
    1 shared_load_transactions_per_request 1.000000
    1 shared_store_transactions_per_request 1.000000

    正如期望的那样,load的bank_conflict已经消失。在Fermi上,只需要加上一列就可以解决bank-conflict,但是在Kepler上却不一定,这取决于2D shared Memory的大小,因此对于8-byte模式,可能需要多次试验才能得到正确结果。


    原文链接:http://blog.163.com/wujiaxing009@126/blog/static/71988399201712735436357/

                    https://www.cnblogs.com/1024incn/p/4605502.html

    展开全文
  • Oracle 12C In-Memory特性研究

    千次阅读 2019-02-06 18:14:04
    Oracle 12C In-Memory特性研究一、Oracle In-Memory1.1 In-Memory 开启方法1.2 开启与关闭IM column store1.3 inmemory优先级调整1.4 加载对象到IM二、In-Memory测试2.1 全字段查询2.2 索引字段比较测试2.3 批量...

    一、Oracle In-Memory

    行格式与列格式:

    Oracle 数据库传统上以行格式存储数据。在行格式数据库中,数据库中存储的每个新事务或新记录都表示为表中的一个新行,而在查询数据时是利用传统BUFFER CACHE。

    列格式数据库将表以单独的列结构存储到内存中。列格式适用于报表类,分析,选择少量列但是查询要访问大部分的数据的场景。
    在这里插入图片描述

    1.1 In-Memory 开启方法

    启用IMO非常简单,12.1.0.2及之后版本下,设置INMEMORY_SIZE 为非0值便可启用IM column store特性。

    INMEMORY_SIZE 是个实例级参数,默认为0,设置一个非0值时,最小值为100M。

    通常情况下,sys用户下的对象及SYSTEM、SYSAUX表空间上的对象无法使用IMO特性,但通过设置“_enable_imc_sys”隐含参数也可以使用

    开启DB In-Memory过程如下:
    1、修改INMEMORY_SIZE参数:
    SQL> ALTER SYSTEM SET INMEMORY_SIZE=1G SCOPE=SPFILE;

    2、检查sga参数的设置,确保在设置完inmemroy_size参数之后数据库实例还可以正常启动。如果数据库使用了ASMM,则需要检查sga_target参数。如果使用了AMM,则需要检查MEMORY_TARGET参数,同时也需要检查SGA_MAX_TARGET(或MEMORY_MAX_TARGET)。

    备注:从 12.2 开始,可以动态增加 In-Memory 区域的大小,为此,只需 通过 ALTER SYSTEM 命令增加 INMEMORY_SIZE 参数值即可

    3、重启数据库实例

    4、查看IM特性是否开启

    SQL> SHOW PARAMETER inmemory;
    NAME                                 TYPE        VALUE
    ------------------------------------ ----------- ------------------------------
    inmemory_adg_enabled                 boolean     TRUE
    inmemory_clause_default              string
    inmemory_expressions_usage           string      ENABLE
    inmemory_force                       string      DEFAULT
    inmemory_max_populate_servers        integer     2
    inmemory_query                       string      ENABLE
    inmemory_size                        big integer 1G
    inmemory_trickle_repopulate_servers_ integer     1
    percent
    inmemory_virtual_columns             string      MANUAL
    optimizer_inmemory_aware             boolean     TRUE
    

    1.2 开启与关闭IM column store

    1、TABLE 级启用:

    可以通过如下初始建表或后续修改表 inmemory 属性的方式进行启用:
    create table test (id number) inmemory;
    alter table test inmemory;
    

    2、COLUMN 级启用:

    仅启用表中某列前,该表必须先设置为 inmemory 模式:
    alter table imo_t1 inmemory (id) no inmemory (name,type); alter table imo_t2 inmemory (name) no inmemory (id,type);
    
    SELECT table_name, segment_column_id seg_col_id, column_name, inmemory_compression FROM v$im_column_level WHERE owner = 'IMOTEST' and table_name in ('IMO_T1','IMO_T2') ORDER BY 1,3;
    
                    
    TABLE_NAME SEG_COL_ID COLUMN_NAME   INMEMORY_COMPRESSION    
    ---------- ---------- --------------- -----------------------   
    IMO_T1           1          ID          DEFAULT 
    IMO_T1           2          NAME        NO INMEMORY 
    IMO_T1           3          TYPE        NO INMEMORY 
    IMO_T2           1          ID          NO INMEMORY 
    IMO_T2           2          NAME        DEFAULT 
    IMO_T2           3          TYPE        NO INMEMORY
    

    3、表空间级启用:

    可以通过如下初始创建表空间或后续修改表空间 inmemory 属性的方式进行启用,在属性为 inmemory 的表空间中创建的对象自动加载 inmemory 属性,除非显示设置对象为 no inmemory:
    create tablespace imotest datafile '/u01/app/oracle/oradata/orcl/imotest01.dbf' size 100M default inmemory;alter tablespace imotest default inmemory;
    select tablespace_name, def_inmemory from dba_tablespaces where tablespace in ('IMOTEST');
    
    TABLESPACE_NAME                 DEF_INMEMORY
    ------------------------------ ---------------
    IMOTEST                         ENABLED
    

    4、如果需要知道具体哪些列开启了IM column store则需要到V$IM_COLUMN_LEVEL中进行查看

    SQL> SELECT TABLE_NAME, COLUMN_NAME, INMEMORY_COMPRESSION FROM V$IM_COLUMN_LEVEL WHERE TABLE_NAME = 'TBNAME';
    

    5、查询有关IM列表属性

    SQL> SELECT OWNER, SEGMENT_NAME,bytes,INMEMORY_SIZE,POPULATE_STATUS, BYTES_NOT_POPULATED FROM V$IM_SEGMENTS;
    
    OWNER      SEGMENT_NA      BYTES INMEMORY_SIZE POPULATE_STAT BYTES_NOT_POPULATED
    ---------- ---------- ---------- ------------- ------------- -------------------
    CS         MEM         391880704      52428800 COMPLETED                       0
    CS         TEST         99426304      15138816 COMPLETED                       0
    CS         DUP           5095424       3407872 COMPLETED                       0
    

    6、关闭inmemory

    alter table test no inmemory;
    

    1.3 inmemory优先级调整

    启用了 IMO 的对象,会按照一定的优先级进入 SGA 中配置好的 IN-MEMORY 区域,同时,在 IN-MEMORY 区域用满后,依次置换出优先级较低的对象。下表为关于 IMO 对象优先级说明:

    优先级描述

    PRIORITY NONE	缺省级别;执行 SQL 引起对象扫描后,触发进入 IN-MEMORY
    PRIORITY CRITICAL	最高优先级;数据库启动后立即进入 IN-MEMORY
    PRIORITY HIGH	在具有 CRITICAL 优先级的对象之后进入 IN-MEMORY
    PRIORITY MEDIUM	在具有 CRITICAL、HIGH 优先级的对象之后进入 IN-MEMORY
    PRIORITY LOW	在具有 CRITICAL、HIGH、MEDIUM 优先级的对象之后进入 IN-MEMORY
    

    修改示例:

    SQL> alter table test inmemory priority high;
    
    SQL> col owner format a30
    
    SQL> col segment_name format a30
    
    SQL> SELECT INMEMORY,INMEMORY_PRIORITY,INMEMORY_COMPRESSION,INMEMORY_DISTRIBUTE, INMEMORY_DUPLICATE
    FROM USER_TABLES WHERE TABLE_NAME = 'TEST';
    INMEMORY INMEMORY INMEMORY_COMPRESS INMEMORY_DISTRI INMEMORY_DUPL
    -------- -------- ----------------- --------------- -------------
    ENABLED  HIGH     FOR QUERY LOW     AUTO            NO DUPLICATE
    

    1.4 加载对象到IM

    1、通过全表扫描objects加载数据到IM

    SQL> SELECT /*+ FULL (s) */ COUNT(*) FROM table s;
    查询V$IM_SEGMENTS中的数据
    SQL> col owner for a10
    
    SQL> col SEGMENT_NAME for a10
    
    SQL> SELECT OWNER, SEGMENT_NAME, POPULATE_STATUS, BYTES_NOT_POPULATED FROM V$IM_SEGMENTS;
     
    OWNER      SEGMENT_NA POPULATE_ BYTES_NOT_POPULATED
    
    ---------- ---------- --------- -------------------
    
    CS    TEST      COMPLETED                   0
    

    2、DBMS_INMEMORY来加载数据

    DBMS_INMEMORY包提供了两个PROCEDURE来手工加载数据到IM中:

    POPULATE:强制加载给定的表

    REPOPULATE:强制重新加载给定的表,在该表已经至少加载过一次之后才可使用。

    手工执行DBMS_INMEMORY.POPULATE procedure来加载TEST表到IM中
    SQL> EXEC DBMS_INMEMORY.POPULATE('CS','TEST');
    

    通过DBMS_INMEMORY.REPOPULATE prcedure及FORCE=>TRUE选项来加载TEST表到IM中。FORCE=>TRUE选项强制进行一次完整重新载入,类似于full refresh

    SQL> EXEC DBMS_INMEMORY.REPOPULATE('CS','TEST', FORCE=>TRUE);
    

    3、设置PRIORITY clause自动加载数据
    将测试表TEST的PRIORITY级别改为HIGH。

    SQL> ALTER TABLE test INMEMORY PRIORITY HIGH|MEDIUM|LOW;
    

    二、In-Memory测试

    2.1 全字段查询

    通过CTAS方式创建表TEST,普通行式扫描与开启inmemory特性分别测试,比对执行计划。

    create table test as select * from dba_objects;
    

    no inmemory查询测试

    set timing on
    set autotrace traceonly
    set pagesize 200 linesize 200
    col TABLE_NAME for a20
    col INMEMORY_PRIORITY for a20
    col INMEMORY_DISTRIBUTE for a20
    col INMEMORY_COMPRESSION for a20
    

    全字段查询,执行计划

    SQL> select count(*) from test;
    COUNT(*)
    ----------
         74329
    Elapsed: 00:00:00.01
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1950795681
    
    -------------------------------------------------------------------
    | Id  | Operation          | Name | Rows  | Cost (%CPU)| Time     |
    -------------------------------------------------------------------
    |   0 | SELECT STATEMENT   |      |     1 |   403   (1)| 00:00:01 |
    |   1 |  SORT AGGREGATE    |      |     1 |            |          |
    |   2 |   TABLE ACCESS FULL| TEST | 74329 |   403   (1)| 00:00:01 |
    -------------------------------------------------------------------
    
    
    Statistics
    ----------------------------------------------------------
              0  recursive calls
              5  db block gets
           1460  consistent gets
              0  physical reads
              0  redo size
            544  bytes sent via SQL*Net to client
            608  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              1  rows processed
    

    开启in memory查询测试

    SQL> alter table test inmemory;
    
    SQL> select TABLE_NAME,INMEMORY_PRIORITY,INMEMORY_DISTRIBUTE,INMEMORY_COMPRESSION from user_tables;
    
    TABLE_NAME           INMEMORY_PRIORITY    INMEMORY_DISTRIBUTE  INMEMORY_COMPRESSION
    -------------------- -------------------- -------------------- --------------------
    TEST                 NONE                 AUTO                 FOR QUERY LOW
    
    已开启inmemory
    
    SQL> select pool,ALLOC_BYTES/1024/1024,USED_BYTES/1024/1024,POPULATE_STATUS,con_id 
    from V$INMEMORY_AREA;
    
    POOL          ALLOC_BYTES/1024/1024 USED_BYTES/1024/1024 POPULATE_STATUS      CON_ID
    ------------  ------------          --------------------- ---------- ------------------
    1MB POOL          815                    0                DONE                      3
    64KB POOL         192                    0                DONE                      3
    --因为只是把该表设置了INMEMORY,但是未查询过,所以查询V$INMEMORY_AREA中未使用相关内存--
    

    全字段查询,执行计划
    第一次执行:

    SQL> select count(*) from test;
    
      COUNT(*)
    ----------
         74329
    
    Elapsed: 00:00:00.05
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1950795681
    
    ----------------------------------------------------------------------------
    | Id  | Operation                   | Name | Rows  | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |      |     1 |   403   (1)| 00:00:01 |
    |   1 |  SORT AGGREGATE             |      |     1 |            |          |
    |   2 |   TABLE ACCESS INMEMORY FULL| TEST | 74329 |   403   (1)| 00:00:01 |
    ----------------------------------------------------------------------------
    
    
    Statistics
    ----------------------------------------------------------
              5  recursive calls
              5  db block gets
           1467  consistent gets
              0  physical reads
              0  redo size
            544  bytes sent via SQL*Net to client
            608  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              2  sorts (memory)
              0  sorts (disk)
              1  rows processed
    

    第二次执行:

    Elapsed: 00:00:00.03
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1950795681
    
    ----------------------------------------------------------------------------
    | Id  | Operation                   | Name | Rows  | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |      |     1 |    16   (7)| 00:00:01 |
    |   1 |  SORT AGGREGATE             |      |     1 |            |          |
    |   2 |   TABLE ACCESS INMEMORY FULL| TEST | 74329 |    16   (7)| 00:00:01 |
    ----------------------------------------------------------------------------
    
    
    Statistics
    ----------------------------------------------------------
              0  recursive calls
              3  db block gets
              9  consistent gets
              0  physical reads
              0  redo size
            544  bytes sent via SQL*Net to client
            608  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              1  rows processed
    

    查询inmemory内存使用:

    SQL> select pool,ALLOC_BYTES/1024/1024,USED_BYTES/1024/1024,POPULATE_STATUS,con_id 
    from V$INMEMORY_AREA;
    
    POOL                       ALLOC_BYTES/1024/1024 USED_BYTES/1024/1024 POPULATE_STATUS                CON_ID
    -------------------------- --------------------- -------------------- -------------------------- ----------
    1MB POOL                                     815                    4 DONE                                3
    64KB POOL                                    192                  .25 DONE                                3
    --再次查看,已经使用了分配的In-Memory中内存
    

    性能比对:

    sql planno-inmemoryinmemory
    consistent gets14609
    physical reads00
    Cost40316

    结果:
    开启inmemory之后性能提升162倍

    2.2 索引字段比较测试

    在已开启IMO特性条件下,通过给表test增加列索引,比较IM与索引执行计划
    1、在object_name上创建索引

    SQL> create index idx_test_OBname on test(OBJECT_NAME);
    

    2、查看表TEST是否加载到IM中

    col owner for a20
    col SEGMENT_NAME for a20
    col POPULATE_STATUS for a20
    col BYTES_NOT_POPULATED for 99999
    
    SELECT OWNER, SEGMENT_NAME, POPULATE_STATUS, BYTES_NOT_POPULATED FROM V$IM_SEGMENTS;
    OWNER                SEGMENT_NAME         POPULATE_STATUS      BYTES_NOT_POPULATED
    -------------------- -------------------- -------------------- -------------------
    CS                   TEST                 COMPLETED                              0
    表已被加入到IM中
    

    3、使用索引简单列查询

    SQL> set autotrace traceonly
    SQL> select count(*) from test where object_name='TEST';
    
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 3197243274
    
    -------------------------------------------------------------------------------------
    | Id  | Operation         | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
    -------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |                 |     1 |    35 |     3   (0)| 00:00:01 |
    |   1 |  SORT AGGREGATE   |                 |     1 |    35 |            |          |
    |*  2 |   INDEX RANGE SCAN| IDX_TEST_OBNAME |    10 |   350 |     3   (0)| 00:00:01 |
    -------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - access("OBJECT_NAME"='TEST')
    
    
    Statistics
    ----------------------------------------------------------
              2  recursive calls
              0  db block gets
              6  consistent gets
              2  physical reads
              0  redo size
            542  bytes sent via SQL*Net to client
            607  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              1  rows processed
              
              逻辑读:6
              物理:2
    

    4、强制全表扫描查询

    SQL> select /*+full(s)*/count(*) from test s where object_name='test';
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1950795681
    
    ------------------------------------------------------------------------------------
    | Id  | Operation                   | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    ------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |      |     1 |    35 |   124   (1)| 00:00:01 |
    |   1 |  SORT AGGREGATE             |      |     1 |    35 |            |          |
    |*  2 |   TABLE ACCESS INMEMORY FULL| TEST |     9 |   315 |   124   (1)| 00:00:01 |
    ------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - inmemory("OBJECT_NAME"='test')
           filter("OBJECT_NAME"='test')
    
    
    Statistics
    ----------------------------------------------------------
              1  recursive calls
              0  db block gets
             10  consistent gets
              0  physical reads
              0  redo size
            541  bytes sent via SQL*Net to client
            607  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              1  rows processed
              
    逻辑读:10
    物理读:0
    

    总结:在数据离散度较高,且通过索引条件过滤的扫描场景中,IM特性对性能并没有提升,传统的索引+行式存储的执行计划已经足够,在默认情况下还是会根据查询索引返回rowid的方式查找数据。

    2.3 批量update测试

    1、创建测试表disk、emp,分别为im表以及rows表,总数相同

    SQL> create table disk as select * from dba_objects;
    SQL> insert into disk select * from disk;
    
    74360 rows created.
    
    SQL> /
    
    148720 rows created.
    
    SQL> /
    
    297440 rows created.
    
    SQL> /
    
    594880 rows created.
    
    SQL> /
    
    1189760 rows created.
    
    SQL> commit;
    
    Commit complete.
    
    SQL> select count(*) from disk;
    
      COUNT(*)
    ----------
       2379520
       
      SQL> create table mem as select * from disk inmemory; 
    

    更新磁盘表
    update disk set owner=‘tom’;
    更新内存表
    update mem set owner=‘tom’;

    普通表:
    时间:14.49
    逻辑读:3202294+894128
    物理读:5602
    cost:403

    IM表:
    时间:18.94
    逻辑读:3231179+254
    物理读:92476
    cost:483

    总结:IM特性在update性能有所下降

    2.4 大批量insert测试

    从磁盘插到磁盘
    insert into disk select * from cs;
    从磁盘插到内存
    insert into mem select * from cs;

    普通表:
    时间:0.13
    逻辑读:9332+2903
    物理读:2895
    cost:404

    IM表:
    时间:0.17
    逻辑读:3231179+254
    物理读:92476
    cost:483

    2.5 大量delete测试

    delete from disk where rownum <10000;
    delete from mem where rownum <10000;
    普通表:
    时间:0.08
    逻辑读:11470+202
    物理读:253
    cost:12986

    IM表:
    时间:0.07
    逻辑读:11472+9
    物理读:0
    cost:493

    2.6 压缩方式测试

    压缩方式描述
    NO MEMCOMPRESSIMO 中存储无压缩
    MEMCOMPRESS FOR DML最小化压缩,优化 DML 操作
    MEMCOMPRESS FOR QUERY LOW缺省方式:查询性能最优、空间压缩效果好于DML方式
    MEMCOMPRESS FOR QUERY HIGH查询性能次优(excellent)、空间压缩效果好于 QUERY LOW
    MEMCOMPRESS FOR CAPACITY LOW查询性能良好(good)、空间压缩效果好于 QUERY HIGH
    MEMCOMPRESS FOR CAPACITY HIGH缺省设置、空间压缩效果最优

    查看压缩比

    col owner for a5
    col SEGMENT_NAME for a10
    col POPULATE_STATUS for a10
    col INMEMORY_COMPRESSION for a10
    SQL> SELECT V.OWNER, V.SEGMENT_NAME,V.BYTES/1024/1024 ORIG_SIZE_MB,V.INMEMORY_SIZE/1024/1024 IN_MEM_SIZE_MB,BYTES_NOT_POPULATED,POPULATE_STATUS status,INMEMORY_COMPRESSION,V.BYTES/V.INMEMORY_SIZE COMP_RATIO FROM V$IM_SEGMENTS V WHERE SEGMENT_NAME = 'TEST';
    
        OWNER SEGMENT_NAME         ORIG_SIZE_MB IN_MEM_SIZE_MB BYTES_NOT_POPULATED STATUS               INMEMORY_COMPRESS COMP_RATIO
    ----- -------------------- ------------ -------------- ------------------- -------------------- ----------------- ----------
    CS    TEST                   1466.78125        110.625                   0 COMPLETED            FOR QUERY LOW     13.2590395
    

    表TEST在磁盘上占用1466MB,采用默认压缩方式,内存中占用110.625MB,压缩比为13.26:1

    压缩比测试:
    表TEST大小1466.78125MB,数据行9514112

    1、NO MEMCOMPRESS:

    alter table test inmemory MEMCOMPRESS NO MEMCOMPRESS;
    逻辑读:14
    物理读:0
    COST: 126
    时间: 0.01
    压缩比:1.19
    

    2、MEMCOMPRESS FOR DML:

    alter table test inmemory MEMCOMPRESS FOR DML;
    逻辑读:14 
    物理读:0
    COST: 126
    时间:0.01
    压缩比:1.22
    

    3、MEMCOMPRESS FOR QUERY LOW:

    alter table test inmemory MEMCOMPRESS FOR QUERY LOW;
    逻辑读:14
    物理读:0
    COST:125
    时间:0.01
    压缩比:7.20
    

    4、MEMCOMPRESS FOR QUERY HIGH:

    alter table test inmemory MEMCOMPRESS FOR QUERY high;
    逻辑读:14
    物理读:0
    COST: 125
    时间:0.01
    压缩比:9.67
    

    5、MEMCOMPRESS FOR CAPACITY LOW:

    alter table test inmemory MEMCOMPRESS FOR CAPACITY LOW;
    逻辑读:14
    物理读:0
    COST: 125
    时间:0.01
    压缩比:12.91
    

    6、MEMCOMPRESS FOR CAPACITY HIGH:

    alter table test inmemory MEMCOMPRESS FOR CAPACITY HIGH;
    逻辑读:14
    物理读:0
    COST: 25
    时间:0.01
    压缩比:19.14
    
    

    测试结果汇总:

    压缩方式压缩比
    NO MEMCOMPRESS1.19
    MEMCOMPRESS FOR DML1.22
    MEMCOMPRESS FOR QUERY LOW7.20
    MEMCOMPRESS FOR QUERY HIGH9.67
    MEMCOMPRESS FOR CAPACITY LOW12.91
    MEMCOMPRESS FOR CAPACITY HIGH19.14

    总结:压缩方式不同,表加载到IM中的时间也会不一样。压缩比越大加载到内存中的时间越长。而对于select查询消耗时间不影响。

    2.7 查询大量列性能测试

    三、评估对象在IMO大小

    DBMS_COMPRESSION.GET_COMPRESSION_RATIO
    在对一张表使用COMPRESSION clause进行IM压缩级别设置之前,我们可以通过Oracle的COMPRESSION ADVISOR对表放入到IM中的大小进行提前计算。

    SET SERVEROUTPUT ON
    
    DECLARE
    
    l_blkcnt_cmp PLS_INTEGER;
    
    l_blkcnt_uncmp PLS_INTEGER;
    
    l_row_cmp PLS_INTEGER;
    
    l_row_uncmp PLS_INTEGER;
    
    l_cmp_ratio PLS_INTEGER;
    
    l_comptype_str VARCHAR2(100);
    
    BEGIN
    
    dbms_compression.get_compression_ratio (
    
    -- Input parameters
    
    scratchtbsname => 'CS',
    
    ownname => 'CS',
    
    objname => 'TEST',
    
    subobjname => NULL,
    
    comptype => dbms_compression.comp_inmemory_QUERY_LOW,
    
    -- Output parameter
    
    blkcnt_cmp => l_blkcnt_cmp,
    
    blkcnt_uncmp => l_blkcnt_uncmp,
    
    row_cmp => l_row_cmp,
    
    row_uncmp => l_row_uncmp,
    
    cmp_ratio => l_cmp_ratio,
    
    comptype_str => l_comptype_str,
    
    subset_numrows => dbms_compression.comp_ratio_allrows);
    
    dbms_output.put_line('Comp. ratio (QUERY LOW):'||l_cmp_ratio);
    
    END;
    
    /
    

    Comp. ratio (QUERY LOW):7
    估计结果压缩比7,实际压缩比为7.20

    #五、RAC环境测试
    rac环境独有参数DUPLICATE clause、DISTRIBUTE clause:

    DUPLICATE clause:
    此参数为EXADATA一体机专用,在RAC环境中,每个节点拥有自己的IM Area。一个objects根据DUPLICATE clause的设置将一样的数据加载到多个IM Area中。

    默认是NO DUPLICATE设置,表示在数据库的IM中对一个objects在所有节点中合起来只保存一份。举例说明,比如三节点的RAC中,对于分区表SALES来讲可能2012年份的数据在1节点,2013年份的数据在2节点,2014年份的数据在3节点,每个分区只保存在一个节点上。

    为了提升可用性,也可以设置为DUPLICAET ALL,在每个节点上都保存一份。举例说明,还是刚才那个SALES表的请款下,1,2,3三个节点各保存一份完整sales表数据到各自的IM中。在任意一个节点上都可以获取查询需要的数据。

    在设置为DUPLICATE ALL的情况下

    DISTRIBUTE clause:

    如果一个objects因为太大无法被加载到一个IM Area中,还可以通过DISTRIBUTE clause的设置将它分成几个数据片分别加载到不同的节点中。

    默认情况下DISTRIBUTE clause的默认值为AUTO-DISTRIBUTE,这时候是否将objects分布式分布在不同的节点上由Oracle内部算法决定。这个参数对于单实例没有影响,在RAC环境中,默认存在IM中的表会分布在各个节点之中。

    RAC环境并不像单实例一样只需修改表的IM属性即可启用,如果要使用IMO,必须在系统层面修改“并行度策略”为自动。下面对参数“parallel_degree_policy”,分别测试2个场景

    1、先查看要测试的表TEST是否已加载到IM STORE

    col SEGMENT_NAME for a5
    col POPULATE_STATUS for a10
    col INMEMORY_DISTRIBUTE for a10
    col INMEMORY_DUPLICATE for a20
    
    SQL> select INST_ID,SEGMENT_NAME,INMEMORY_SIZE/1024/1024,BYTES/1024/1024,BYTES_NOT_POPULATED/1024/1024,INMEMORY_DISTRIBUTE,INMEMORY_DUPLICATE,POPULATE_STATUS from gv$im_segments;
    
       INST_ID SEGME INMEMORY_SIZE/1024/1024 BYTES/1024/1024 BYTES_NOT_POPULATED/1024/1024 INMEMORY_D INMEMORY_DUPLICATE   POPULATE_S
    ---------- ----- ----------------------- --------------- ----------------------------- ---------- -------------------- ----------
             2 TEST                    9.125             192                     123.53125 AUTO       NO DUPLICATE         COMPLETED
             1 TEST                  16.1875             192                    66.9140625 AUTO       NO DUPLICATE         COMPLETED
    

    1、开启AUTO DOP

    alter system set parallel_degree_policy=AUTO sid='*';
    alter system set parallel_force_local=false sid='*';
    alter system flush buffer_cache;
    alter system flush shared_pool;
    

    2、查看执行计划

    SQL> select /*+ parallel */count(*) from test;
    
      COUNT(*)
    ----------
       1455168
    
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 2661943167
    
    -----------------------------------------------------------------------------------------------------------------
    | Id  | Operation                       | Name     | Rows  | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
    -----------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                |          |     1 |     9   (0)| 00:00:01 |        |      |            |
    |   1 |  SORT AGGREGATE                 |          |     1 |            |          |        |      |            |
    |   2 |   PX COORDINATOR                |          |       |            |          |        |      |            |
    |   3 |    PX SEND QC (RANDOM)          | :TQ10000 |     1 |            |          |  Q1,00 | P->S | QC (RAND)  |
    |   4 |     SORT AGGREGATE              |          |     1 |            |          |  Q1,00 | PCWP |            |
    |   5 |      PX BLOCK ITERATOR          |          | 90948 |     9   (0)| 00:00:01 |  Q1,00 | PCWC |            |
    |   6 |       TABLE ACCESS INMEMORY FULL| TEST     | 90948 |     9   (0)| 00:00:01 |  Q1,00 | PCWP |            |
    -----------------------------------------------------------------------------------------------------------------
    
    Note
    -----
       - automatic DOP: Computed Degree of Parallelism is 2
       - parallel scans affinitized for inmemory
    
    
    Statistics
    ----------------------------------------------------------
            232  recursive calls
              4  db block gets
            163  consistent gets
             15  physical reads
              0  redo size
            545  bytes sent via SQL*Net to client
            551  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
             16  sorts (memory)
              0  sorts (disk)
              1  rows processed   
    
    逻辑读:163
    物理读:15
    

    3、不使用并行查询查询

    SQL> select count(*) from test;
    
      COUNT(*)
    ----------
       1455168
    
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1950795681
    
    ----------------------------------------------------------------------------
    | Id  | Operation                   | Name | Rows  | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |      |     1 |    16   (0)| 00:00:01 |
    |   1 |  SORT AGGREGATE             |      |     1 |            |          |
    |   2 |   TABLE ACCESS INMEMORY FULL| TEST | 90948 |    16   (0)| 00:00:01 |
    ----------------------------------------------------------------------------
    
    Note
    -----
       - automatic DOP: Computed Degree of Parallelism is 1 because of no expensive parallel operation
    
    
    Statistics
    ----------------------------------------------------------
              3  recursive calls
              0  db block gets
           9081  consistent gets
           9077  physical reads
              0  redo size
            545  bytes sent via SQL*Net to client
            551  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              1  rows processed
    
    逻辑读:9081
    物理读:9077
    

    4、关闭AUTO DOP

    alter system set parallel_degree_policy=MANUAL sid='*';
    alter system set parallel_force_local=false sid='*';
    alter system flush buffer_cache;
    alter system flush shared_pool;
    

    5、查看执行计划

    SQL> select /*+ parallel */count(*) from test;
    
      COUNT(*)
    ----------
       1455168
    
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 2661943167
    
    -----------------------------------------------------------------------------------------------------------------
    | Id  | Operation                       | Name     | Rows  | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
    -----------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                |          |     1 |     9   (0)| 00:00:01 |        |      |            |
    |   1 |  SORT AGGREGATE                 |          |     1 |            |          |        |      |            |
    |   2 |   PX COORDINATOR                |          |       |            |          |        |      |            |
    |   3 |    PX SEND QC (RANDOM)          | :TQ10000 |     1 |            |          |  Q1,00 | P->S | QC (RAND)  |
    |   4 |     SORT AGGREGATE              |          |     1 |            |          |  Q1,00 | PCWP |            |
    |   5 |      PX BLOCK ITERATOR          |          | 90948 |     9   (0)| 00:00:01 |  Q1,00 | PCWC |            |
    |   6 |       TABLE ACCESS INMEMORY FULL| TEST     | 90948 |     9   (0)| 00:00:01 |  Q1,00 | PCWP |            |
    -----------------------------------------------------------------------------------------------------------------
    
    Note
    -----
       - automatic DOP: Computed Degree of Parallelism is 2
       - parallel scans affinitized for inmemory
    
    
    Statistics
    ----------------------------------------------------------
            209  recursive calls
              4  db block gets
          17909  consistent gets
          17766  physical reads
              0  redo size
            545  bytes sent via SQL*Net to client
            551  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
             16  sorts (memory)
              0  sorts (disk)
              1  rows processed
    
        逻辑读:17909
        物理读:17766
    

    总结:
    1、调整系统参数(parallel_degree_policy)之后,rac环境下的IM列查询大幅降低了逻辑读与物理读。

    2、在多实例的并发查询中实例之间传输的并不是IMCU,而是每个节点都会对本节点的数据运行相同的sql语句,之后把自己的结果集发送给发起sql语句的实例,组成最终的结果返回给用户。

    parallel_degree_policyAUTOMANUAL
    逻辑读16317909
    物理读1517766

    备注:
    在没有显式使用并行sql时,rac环境im全表扫描并没有使用并行。oracle的优化器会通过一系列的计算比较cost。

    SQL> select count(*) from test;
    执行计划Note
    -----
    automatic DOP: 
    Computed Degree of Parallelism is 1 because of no expensive parallel operation
    

    In some cases, even with Auto DOP set correctly, the optimizer may calculate the cost of a serial access to be less than the cost of a parallel access. This has been identified as bug 18960760, and will usually only happen when very smalltables in the IM column store are involved in the query.

    来自Oracle Blog
    https://blogs.oracle.com/in-memory/oracle-database-in-memory-on-rac-part-i
    

    四、参考文献

    1、Oracle Database In-Memory on RAC - Part I
    https://blogs.oracle.com/in-memory/oracle-database-in-memory-on-rac-part-i

    2、Oracle 12c DB In-Memory入门实验手册
    https://blog.csdn.net/badly9/article/details/49777993

    3、Oracle12c IMO 测试
    https://www.jianshu.com/p/966ee0182e1c

    4、rac并行查询
    http://blog.sina.com.cn/s/blog_74a7d3390102wegl.html

    5、Oracle In-Memory白皮书
    http://www.oracle.com/technetwork/cn/database/in-memory/overview/twp-oracle-database-in-memory-2245633-zhs.pdf

    展开全文
  • oracle 19c Inmemory功能初步测试

    千次阅读 2020-03-27 10:36:27
    测试下IN MEMORY功能到底有多少提高; 查看是否开通in memory的功能,可以看到我已经开通了,如未开通,跳到步骤2,开通了就直接跳到3: TEST@abc>show parameter inmemory NAME TYPE VALUE -------------...

    oracle 19c Inmemory功能初步测试

    IN MEMORY适用与不适用区域

    inmemory适用于:

    1. 可以在以下级别启用In-Memory Column Store

      .列
      .表
      .物化视图
      .表空间 => 如果在表空间级别启用In-Memory Column Store,那么所有存储在该表空间中的所有表与物化视图将抽默认启用In-Memory Column Store。可以将一个数据库对象的所有列或者将一个数据库对象的部分列加载到In-Memory Column Store中。类似地,对于分区表或物化视图,可以将所有分区或部分分区加载到In-Memory Column Store中
      .分区
      
    2. 在In-Memory Column Store中存储数据库对象可以显然提高对数据库对象执行以下类型操作的性能:

      .查询扫描大量数据并且使用=,< ,>与in操作来进行过滤
      .查询从表中或者从有大量列的物化视图中选择少量列,比如从有100列的表中选择5列
      .查询对小表与大表进行关联
      .查询将聚集数据
      

    inmemory不适用于:

    1. In-Memory Column Store不能对以下操作类型提高性能:

      .有复杂谓词的查询
      .选择大量列的查询
      .返回大量数据行的查询
      .使用大表联接的查询
      

    IN MEMORY实践测试

    inmemory开启关闭

    inmemory开启前准备

    1. 查看是否开启inmemory功能,inmemory_size为0,默认是关闭的
      SYS@test>show parameter inmemory

      NAME				     TYPE	 VALUE
      ------------------------------------ ----------- ------------------------------
      inmemory_adg_enabled		     boolean	 TRUE
      inmemory_automatic_level	     string	 OFF
      inmemory_clause_default 	     string
      inmemory_expressions_usage	     string	 ENABLE
      inmemory_force			     string	 DEFAULT
      inmemory_max_populate_servers	     integer	 0
      inmemory_optimized_arithmetic	     string	 DISABLE
      inmemory_prefer_xmem_memcompress     string
      inmemory_prefer_xmem_priority	     string
      inmemory_query			     string	 ENABLE
      inmemory_size			     big integer 0
      inmemory_trickle_repopulate_servers_ integer	 1
      percent
      inmemory_virtual_columns	     string	 MANUAL
      inmemory_xmem_size		     big integer 0
      optimizer_inmemory_aware	     boolean	 TRUE
      

    inmemory开启

    1. 启用IMO非常简单,12.1.0.2及之后版本下,设置INMEMORY_SIZE 为非0值便可启用IM column store特性,最小值为100M。通常情况下,sys用户下的对象及SYSTEM、SYSAUX表空间上的对象无法使用IMO特性,但通过设置“_enable_imc_sys”隐含参数也可以使用

    2. 检查sga参数的设置,确保在设置完inmemroy_size参数之后数据库实例还可以正常启动。如果数据库使用了ASMM,则需要检查sga_target参数。如果使用了AMM,则需要检查MEMORY_TARGET参数,同时也需要检查SGA_MAX_TARGET(或MEMORY_MAX_TARGET)
      我的测试环境memory_target才给了2G,分配给inmemory_target 1G (alter system set inmemory_size=1g scope=spfile;) ,重新启动启动的时候,报错:

      ORA-00838: Specified value of MEMORY_TARGET is too small, needs to be at least 2528M
      ORA-01078: failure in processing system parameters
      

      就按照建议的值修改就行,这里我设置成4G
      alter system set memory_target=4g scope=spfile;

    3. 查看参数是否开启 => show parameter inmemory

      NAME				     TYPE	 VALUE
      ------------------------------------ ----------- ------------------------------
      inmemory_adg_enabled		     boolean	 TRUE
      inmemory_automatic_level	     string	 OFF
      inmemory_clause_default 	     string
      inmemory_expressions_usage	     string	 ENABLE
      inmemory_force			     string	 DEFAULT
      inmemory_max_populate_servers	     integer	 16
      inmemory_optimized_arithmetic	     string	 DISABLE
      inmemory_prefer_xmem_memcompress     string
      inmemory_prefer_xmem_priority	     string
      inmemory_query			     string	 ENABLE
      inmemory_size			     big integer 1G
      inmemory_trickle_repopulate_servers_ integer	 1
      percent
      inmemory_virtual_columns	     string	 MANUAL
      inmemory_xmem_size		     big integer 0
      optimizer_inmemory_aware	     boolean	 TRUE
      

    inmemory开启关闭

    1. 关闭Inmemory功能,设置inmemory_size=0,即可,重启数据库

    inmemory性能对比

    创建测试表和索引

    1. 创建测试表

      TEST@testc>create table t_obj as select * from dba_objects;
      
      Table created.
      
    2. 创建索引

      TEST@test>create index object_name_ind on t_obj(object_name);
      
      Index created.
      
    3. 查看inmemory是否有测试表,理论上是没有了,只是确认下哈

      SYS@test>SELECT owner,obj_num,table_name,column_name,inmemory_compression FROM V$IM_COLUMN_LEVEL WHERE OWNER<>'SYS';
      
      no rows selected
      

    表放到inmemory内存区域前执行计划

    可以看到走的是新建的索引,2 physical reads,191 consistent gets,cost也在2左右,可以说性能还可以

    	TEST@test>select * from t_obj where object_name='123';
    	
    	no rows selected
    	
    	
    	Execution Plan
    	----------------------------------------------------------
    	Plan hash value: 1129708809
    	
    	------------------------------------------------------------------------------------------------------
    	| Id  | Operation			    | Name	      | Rows  | Bytes | Cost (%CPU)| Time
    	------------------------------------------------------------------------------------------------------
    	|   0 | SELECT STATEMENT		    |		      |     1 |   115 |     2	(0)| 00:00:01
    	|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| T_OBJ	      |     1 |   115 |     2	(0)| 00:00:01
    	|*  2 |   INDEX RANGE SCAN		    | OBJECT_NAME_IND |     1 |       |     1	(0)| 00:00:01
    	------------------------------------------------------------------------------------------------------
    	
    	Predicate Information (identified by operation id):
    	---------------------------------------------------
    	
    	   2 - access("OBJECT_NAME"='123')
    	
    	
    	Statistics
    	----------------------------------------------------------
    		 98  recursive calls
    		  0  db block gets
    		191  consistent gets
    		  2  physical reads
    		  0  redo size
    	       2375  bytes sent via SQL*Net to client
    		394  bytes received via SQL*Net from client
    		  1  SQL*Net roundtrips to/from client
    		  6  sorts (memory)
    		  0  sorts (disk)
    		  0  rows processed
    

    表放到inmemory内存区域后执行计划

    1. 把整个表放到inmemory的内存中

      TEST@test>alter table t_obj inmemory;
      
      Table altered.
      
    2. 查看字典表是否有t_obj的测试表,直接屏幕输出格式全变了,我也懒得格式化了,直接用TOAD查询出来,截图下哈:
      在这里插入图片描述

    3. 刷新下缓冲池

       alter system flush shared_pool;
      
    4. 再次查看同样语句的执行计划,第一次加载表表到Inmemory内存中,有点消耗,效率不会那么高,主要是第二次和第N次的效率,这里,我放的是加载到INMEMORY内存中的第二次的执行计划

       TEST@test>select * from t_obj where object_name='123';
      
      no rows selected
      
      
      Execution Plan
      ----------------------------------------------------------
      Plan hash value: 1129708809
      
      -------------------------------------------------------------------------------------------------------
      | Id  | Operation			    | Name	      | Rows  | Bytes | Cost (%CPU)| Time |
      -------------------------------------------------------------------------------------------------------
      |   0 | SELECT STATEMENT		    |		      |     1 |   115 |     2	(0)| 00:00:01 |
      |   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| T_OBJ	      |     1 |   115 |     2	(0)| 00:00:01 |
      |*  2 |   INDEX RANGE SCAN		    | OBJECT_NAME_IND |     1 |       |     1	(0)| 00:00:01 |
      -------------------------------------------------------------------------------------------------------
      
      Predicate Information (identified by operation id):
      ---------------------------------------------------
      
         2 - access("OBJECT_NAME"='123')
      
      
      Statistics
      ----------------------------------------------------------
      	  0  recursive calls
      	  0  db block gets
      	  2  consistent gets
      	  0  physical reads
      	  0  redo size
             2375  bytes sent via SQL*Net to client
      	394  bytes received via SQL*Net from client
      	  1  SQL*Net roundtrips to/from client
      	  0  sorts (memory)
      	  0  sorts (disk)
      	  0  rows processed
      

    in memory的原理详细讲解如下,直接拷贝过来,留着自己研读下吧

    随着Oracle 12c推出了in memory组件,使得Oracle数据库具有了双模式数据存放方式,从而能够实现对混合类型应用的支持:传统的以行形式保存的数据满足OLTP应用;列形式保存的数据满足以查询为主的OLAP应用。in memory组件可以和其他数据库组件功能使用,并不需要用户单独开发或者修改应用程序,就可以非常方便的实现基于实时数据库分析的转变。本文会介绍in memory组件的一些相关知识,包含了以下的内容:

    -列式存储的基本知识
    -访问in memory area中的数据
    -In memory和RAC的融合

    1.列式存储的基本知识。

    1.1内存结构

    传统的数据库采用的是行式存储,当一个事务发生时,oracle会对一行(或多行)数据进行操作,也就是说数据的操作单位是一行数据,即使可能需要被访问的数据只是其中的几个列,这种数据保存方式对以DML为主的OLTP应用是非常适合,也是非常高效的。但是在OLAP系统当中,针对大量数据的查询操作是占绝对地位的,而这些查询往往只针对表中一些特定的列。另外,数据的改变都是以数据装载的方式发生的,也就是说数据被装载到数据库后是极少发生改变的,毫无疑问以列的方式组织数据无疑是更好的选择。正是因为这两种存放数据的方式各有利弊,无论以哪一种方式来保存数据都无法很好的满足混合式应用的数据库系统的要求,Oracle推出了所谓的双模式数据存放方式:在磁盘(也就是数据文件)和database buffer cache中以行的形式存放数据;单独开辟一块内存空间(in memory area),其中以列的方式保存数据,满足OLAP类型的查询需求。而Oracle之所以选择单独开辟一块内存来保存列模式数据的主要原因之一就是OLAP的应用是以查询为主的,而且数据改变的发生方式绝大部分都是以数据加载的方式发生的,这意味着oracle完全也通过批量数据加载的方式来完成in memory area空间中的数据加载从而保证数据的实时性。接下来,从in memory area内存结构,数据加载过程两个方面来介绍in memory组件的一些基本知识。

    首先,in memory area是独立于传统的SGA和PGA的单独的内存空间,由1Mpool和64Kpool两部分构成。其中1M pool用于保存列格式的数据,IMCU(in memoryCompressionUnit)是基本的存储单位;64Kpool用于保存和IMCU相对的元数据信息,SMU(SnapshotMetadataUnit)是这部分内存的基本单位。读者可以通过下面的查询了解相关的信息。
    图片描述
    IMCU是用于在内存中保存列格式数据的基本存储单位,oracle会尽量保证每个IMCU的大小为1M,每个IMCU由图1所示的两部分构成

    图片描述
    图1

    SMU部分主要用于保存IMCU的原数据信息,例如:IMCU对应的指针,IMCU包含的extent范围,DBA范围,Journaltable的指针,Rowid位图等。

    1.2数据加载(populate)

    在了解了in memory如何在内存中保存数据之后,再来看一下数据是如何被加载到内存中的。根据之前内容的介绍,数据在数据文件中是以行格式来保存的,那么就需要一种机制来把数据加载到in memory area当中,并且在加载过程当中完成从行模式到列模式的转变。

    首先,oracle支持对表,分区或表空间指定in memory属性,也就是说in memory属性是针对物理数据库对象的,而不是逻辑数据库对象的。例如:我们可以使用下面的语句来为数据库对象指定in memory属性:

    SQL>alter table sales inmemory no memcompress priority critical;
    SQL>ALTER TABLESPACE ts_data INMEMORY;
    SQL>ALTER TABLE sales MODIFY PARTITION SALES_201501 INMEMORY;

    需要说明的是,由于in memory组件主要是针对OLAP应用的,而这种应用绝大部分的操作都是查询,而且很多时候只关心表中特定的一个或多个列,所以in memory特性还可以指定只把表中的特定的一个或多个列加载到in memory area当中。

    由于in memory area区域的大小是有限的,主机的内存资源也是有限的,而数据库的容量往往会超过已有的内存资源,所以Oracle建议将性能要求很高的表装载到in memory area当中,而将性能要求比较低的表保存到闪存或者磁盘上。当然,如果内存资源充足,而且数据库不大,大部分的应用是以查询为主,也可以考虑将所有的表都装载到in memory区域中。另外,也正是由于资源的限制,Oracle允许用户为不同的表设置in memory加载优先级,基本的原则是优先级高的对象被首先加载到in memory区域当中,优先级低的对象需要等到高优先级的对象加载完毕之后才能够被加载。Oracle提供了5种in memory加载优先级,表1包含了每种优先级的详细信息。

    表1
    表1

    另外,由于in memory主要是面向查询为主的OLAP或者决策支持系统,也就是说绝大部分的数据再被装载(Load)到数据库之后就不会再改变了,那么在加载数据的同时对数据进行压缩无疑可以节省内存空间,而且还能够提高查询的效率(主要的原因是很多被查询的列会包含大量的重复值)。所以in memory组件提供了丰富的压缩选项,允许用户在为对象指定in memory选项的同时指定压缩方法。表2列出了支持的压缩级别:

    图片描述

    上表中的压缩比率由上至下,越来越高。以下的sql语句说明在将表salse加载到in memory area时的优先级最高,而且需要使用“memcompress for query”方式进行压缩:SQL>alter table sales inmemory memcompress for query low priority critical;
    如果需要在指定压缩选项之前了解每种压缩选项能够获得的压缩比,可以使用Oracle Compression Advisor(DBMS_COMPRESSION包)来进行估算。

    最后,加载过程是通过后台进程IMCO和工作进程(W00)进程来协同实现的,在数据库启动后或者一些对象的in memory选项被启用后,IMCO进程会创建出一些加载任务,并根据需要分配给若干个工作进程,每个工作进程负责一部分数据的加载工作,当所有工作进程完成了对应部分数据的加载之后,通知IMCO进程加载完成。

    2.In memory的数据一致性

    如果我们的数据库是只读的,那么事情就变得简单多了,因为数据就不会存在一致性问题,但是事实并非如此,对于大部分的数据库,事务处理是一直都会发生的,那么数据的一致性就需要得到保证。对于in memory组件也不例外,如果DML语句修改的数据并没有被加载到in memory区域当中,那么DML语句的修改就仅限于SGA当中;反之如果修改的数据已经被加载到了in memory区域中,那么就需要一种机制来确保数据的一致性。例如:没有被提交的数据不能被看到,而执行改变的会话应该能看到最新的数据。

    Oracle 是通过journal table 的方式来确保数据的一致性的。每个IMCU都会对应一个自己的journal table, 如果DML语句修改的数据包含在IMCU当中,就在journal table 当中把修改后的数据记录下来,我们称之为private journal;当事务提交之后,再把journal table当中对应的记录标识成为shared journal。这样就可以保证查询在访问IMCU时能够获得一致的数据,而如果查询需要的数据在journal table 中也无法找到时,oracle 会自动根据IMCU中记录的Rowid 位图中的信息映射到buffer cache 当中相应的位置来找到满足查询要求的数据。图2描述了journal table和IMCU的基本关系。

    图片描述
    图2

    然而,如果DML 语句不断发生的话,就会使journal table 中的数据越来越多,甚至出现IMCU中大部分的数据都是旧数据,而新数据都保存在journal table中的情况,这对于in memory查询的性能伤害是很大的。所以,Oracle定义了一个阀值(threshold),当IMCU中旧数据的比例达到这个阀值时就会触发重新加载的过程,也就是说,IMCO后台进程会每隔一段时间(默认2分钟)检查一次是否有IMCU 满足重新加载的条件,如果发现了满足条件的IMCU,就会通知W00工作进程对相应的IMCU进行重新加载,但是由于重新加载的成本是比较高的,而且可能会影响一些正在运行的语句,所以Oracle 会采用渐进的方式来对IMCU进行重新加载的操作,也就是每次只选择一部分满足重新加载条件的IMCU进行处理,而具体的程度可以通过INMEMORY_TRICKLE_REPOPULATE_SERVERS_PERCENT参数来进行调整。

    对于事务所产生的journal table对系统产生的额外负载到底有多大,这个是很难进行量化的,因为有太多的因素会对它产生影响,例如加载时采用的压缩方法,改变的方式,应用程序访问数据的行为。但是,仍然有一些基本的原则是可以尽量减少数据改变对in memory 产生的影响的。由于数据再被加载到in memory area时是以extent 为单位的,如果对数据的改变是随机分布到表的各个extent的话,重新加载的成本就会很高,因为这意味着大量的IMCU需要被重新构建;而如果数据的改变能够集中到特定范围的extent中,或者大部分的改变都是数据插入而且使用直接路径加载的话,那么重新加载的成本就会被大大降低。另外的建议就是对尽量使用分区表来保存数据,这样有利于将数据的改变限定到特定的分区当中,而且针对这些分区不使用或者尽量使用 DML,MEMORYCOMPRESS FOR DML这些轻量级的压缩方式。

    3.访问in memory area中的数据

    3.1单表访问

    在数据被加载到in memory区域之后就可以通过sql语句对它们进行访问了。分析型查询的一个很大的特点就是它只关心表当中特定的一些列而不是全部的列,而且这些列的值很多时候会有大量的重复值,并且作为条件的列很多时候都是常见的数据类型(例如:数值,字符串,日期),基于这些特点,Oracle的in memory组件也做了相应的设计来提高这些分析型查询语句的性能。

    首先,在IMCU当中每一个列都会包含对应的字典信息和存储索引信息。在加载过程当中,工作进程会将对应的IMCU中每个列所拥有的不同值编写成一个字典,之后为该列的每一行数据指定一个keyvalue,用这个keyvalue来代替具体的值,这样做既可以节省空间也为将来查询时能够使用CPU的SIMD技术做准备。而存储索引(StorageIndex)实际上是数据仓库中常见的一种技术,他通过记录某一个列的最大值和最小值的方式能够避免访问大量不满足条件的数据。在IMCU中每个列的头信息当中都会保存这个列在对应的IMCU当中的最大值和最小值,以及他们所对应的偏移量。通过这种方法就可以在查询数据时通过对比最大和最小值的方式快速过滤掉不满足条件的数据,而且一旦数据改变影响到了存储索引中的信息,可以快速定位到对应的位置。但是需要指出的是,存储索引并不见得适用于所有的where条件(谓词)。

    另外,由于数据已经被加载到了内存当中,所以绝大部分的操作都是需要通过cpu来实现的,I/O相关的操作基本不会出现了(除非被查询的表有一部分数据还没有被加载到in memory区域中来)。如何能够更加高效的利用CPU资源就成为了决定性能的一个重要因素,所以Oracle采用了SIMD技术(Single Instruction processing Multiple Data values)使CPU能在一个指令当中访问多个数据,但是由于SIMD所支持的指令是有限的,所以这也解释了为什么Oracle在构建IMCU时会为每个列都创建字典信息。图3描述了SIMD访问数据的基本概念.

    图片描述
    图3

    在上图中,sales表被加载到了in memory area当中,而且IMCU中PROMO_ID列的头信息当中也包含了该列的字典信息,该列当中的每一行的值都已经被转换成为了keyvalue,当查询条件为PROMO_ID=9999是,就可以利用SIMD技术使CPU每次比较多行数据,从而极大地提升了查询的性能。

    最后,我们可以通过在执行计划中查找“TABLE ACCESS INMEMORY FULL TEST”信息来确认是否使用了in memory选项访问表。例如:
    图片描述

    3.2多表连接

    除了针对访问表的优化,in memory组件针对表连接也进行了改进,主要的特性有:布隆过滤器和in memory聚合。

    对于布隆过滤器(Bloom Filters),相信大家并不陌生。它的主要作用就是判断某一个数据是否出现在另一个集合当中,或者用于比较大数据集合之间的共同元素。Oracle从10g开始就在处理一些SQL语句中的表连接时使用布隆过滤器。如果表连接中涉及到的表都已经指定了in memory属性,并且已经加载到了in memory area当中,那么优化器会首先选择连接中的一个表(通常是较小的表),对作为链接条件的列进行一系列的hash函数,并产生一个结果位图(bitmap),之后再对另一个表的数据分批进行同样的hash函数,并和之前的结果位图进行比较,在整个过程中并不会产生I/O而且SIMD技术在比较过程中也可以被使用,所以布隆过滤器的引入使in memory在处理表连接时变得更加高效。

    CBO会在制定执行计划时自动判断是否使用布隆过滤器,用户不需要手动指定。如果在执行计划中看到了以下的信息,说明布隆过滤器被使用了。

    图片描述

    在上面的执行计划说明:

    1.首先在in memory area中访问了表“TEST_SMALL”,就是执行计划中的第5步,之后构建了链接使用的过滤器(BF0000),也就是执行计划中的第4步。
    2.之后在in memory area中访问了表“TEST_BIG”,就是执行计划中的第7步,之后使用了之前构建的过滤器。

    3.3多表连接

    在以分析型的查询语句为主的数据仓库应用当中,除了简单的表连接,还经常出现多表的链接,而且经常会包含一些聚合和分组操作,例如数据仓库应用当中的星型查询。针对这种查询,oracle提出了向量分组(VectorGroupBY)特性来提高select语句的性能。向量分组是一个两阶段的过程:

    阶段1:CBO会找到查询中数据量较小的维度表(Dimension table),将满足条件的作为和庞大的事实表(Fact table)进行连接的列找出来并生成向量组(Vector Group)。之后将向量组和需要进行分组或者聚合的事实表中的列组合,形成一个多维数组和若干个临时表。

    阶段2:在事实表上应用上一阶段产生的向量分组,之后向临时表当中添加需要计算分组或聚合结果的列的值。最后将这些临时表的数据应用到多维数组中,计算出最后的分组或者聚合结果。

    在整个过程中向量分组的构建和向量于事实表的比较都是在内存中完成的,而且SIMD也会被使用,所以可以极大的提升这种查询的性能。当然,由于这种操作都是在内存中完成的,所以对系统的内存资源要求也是比较大的,要求运行这种查询的进程拥有足够的PGA空间。下面的执行计划说明了分组向量在查询中的应用:

    图片描述

    根据上面的执行计划:

    -首先,表”TEST_SMALL_1”和”TEST_SMALL_2”被访问,当然它们都已经被加载到了in memory area
    当中。之后分组向量被构建,他们是”KV0000”和”KV0001”,而且在和需要分组的表进行结合后,临时表也被创建了出来,它们是“SYS_TEMP_0FD9D6604_116B7C6”和“SYS_TEMP_0FD9D6604_116B7C6”。
    -表“TEST_BIG”被访问,之后向量分组被应用到了这个表上。然后开始向临时表当中添加分组结果。
    -多维数组中的结果被生成,它是“VW_VT_F486F43F”。最后通过“HASH GROUPBY”的方式完成最后的分组。

    4.in memory和RAC的融合

    延续Oracle新特性的一贯特点,in memory特性也可以和已经存在的其它数据库组件兼容,例如RAC,从而实现系统的高可用性和可扩展性。由于RAC属于典型的share everything结构,它可以同时在多个节点打开相同的数据库,所以对于同一个数据库对象,它可以被加载(populate)到多个节点上去。当然,前提条件是这些节点的数据库实例都设置了in memory area(参数in memory_size不等于0)。既然数据可以被加载到多个节点,那么就意味着我们需要思考两个问题:

    -问题1:如何将数据分布到多个节点。
    -问题2:数据是否有必要在in memory area当中保存冗余来确保高可用性。

    对于数据的分布方式,oracle提供了根据数据的ROWID范围或根据表的分区(或子分区)两种方式来将数据分布到多个节点上。第一种方法是指将表的数据按照rowid的范围划分成若干份,之后将每份数据均匀的加载到不同的节点当中去,这种分布方式比较适用于数据分布不均匀的表,而且应用程序对表的访问在每个实例上都是比较均匀的场景。例如:
    ALTER TABLE test INMEMORY DISTRIBUTE BY ROWID RANGE;
    第二种方式适用于分区表,oracle会根据分区的定义将每个分区加载到不同节点的in memory area当中去,这种分布方式比较适合数据分布均匀的表。如果应用程序对表的访问在每个实例上都是比较均匀的,尤其适合hash分区表。例如:ALTER TABLE lineorder INMEMORY DISTRIBUTE BY PARTITION;

    对于数据是否应该在in memory area中保存冗余,如果是普通的RAC数据库,那么数据并不会在in memory area中保存冗余;而对于Exadata一体机,in memory area中的数据是可以设置冗余的。之所以选择这样做的原因在于,非Exadata一体机的RAC系统的私网配置千差万别,如果选择保存冗余的话,一旦当某一个实例down掉之后,意味着会有大量的数据需要在节点的私网之间进行传输,以便确保数据的冗余,如果私网的性能不能得到保证的时候,这种数据的传输可能消耗大量的时间和网络资源,并导致严重的后果。而Exadata一体机的私网采用光纤网络,而且使用了先进的RDS协议,数据传输可以达到几十G每秒,所以在处理由于节点故障导致的大量私网数据传输时,仍然可以保证集群的私网正常工作。

    另外,由于目前硬件层面的高可用技术已经非常成熟,一个数据库实例或者节点down掉的事故大部分都是一次性的,很快就能恢复。所以Oracle在发现某一个实例或者节点fail之后并不会马上触发数据的重新分布,而是会等待一段时间以便让问题节点或实例能够重新启动并加载自己的数据,只有当等待时间超时之后,其他节点才会触发数据重新分布的过程,将失败节点的in memory area中的数据重新分布到正常节点。基于这种设计模式,建议在使用RAC系统上的in memory选项时应该为每个节点的in memory area预留出一部分空间,以便确保数据重新分配时仍然有足够的空间。
    下面的图4和图5描述了Exadata环境和非Exadata环境in memory area保存数据的区别

    图片描述
    图4-Exadata环境

    图片描述
    图5-非Exadata环境

    根据上面的图形不难发现,在RAC环境下的,每个节点都不会包含表当中的所有数据。所以在RAC环境下,需要启用oracle的自动并行查询(AutoDOP)才能够使用in memory的方式访问加载到in memory area中的表。另外还要说明的是在多实例的并发查询中实例之间传输的并不是IMCU,而是每个节点都会对本节点的数据运行相同的sql语句,之后把自己的结果集发送给发起sql语句的实例,组成最终的结果返回给用户。例如:一个4节点的RAC数据库,表sales已经被加载到了in memory area当中。运行下面的查询:
    select sum(stock) from sales where store_id in (100,200,300) and order_date=to_date(‘2016-01-01’, ‘yyyy-mm-dd’);

    CBO首先会计算使用in memory scan的成本,如果成本最低,CBO就会选择使用在in memory area中访问sales表。接下来,oracle会访问数据字典中的信息,找到这个表被加载到了哪些实例,并在对应的节点启动相应的并发进程(parallelslave),把这个查询语句发送给并发进程运行。每个实例的并发进程运行完对应的sql语句之后,把产生的汇总值发送给发起查询的实例,生成最终的汇总值并返回给客户。在整个过程中,并不是IMCU在实例之间传递,而是汇总值在传递,所以能够避免大量的私网数据通信。

    以上就是作者对oracle 12c in memory组件一些粗浅的介绍,希望对各位使用Oracle数据库进行开发的人员有所帮助,能够在使用了in memoery组件的oracle数据库上开发应用程序时有些借鉴作用

    转:http://blog.sina.com.cn/s/blog_74a7d3390102wegl.html

    文章可以转载,必须以链接形式标明出处。

    展开全文
  • The Garbage Collection Handbook The Art of Automatic Memory Management, Jones, Hosking, Moss, 2012
  • SciTech.NET.Memory.Profiler.v4.0.114.安装_注册机

    千次下载 热门讨论 2013-01-08 11:37:20
    NET Memory Profiler-找到内存泄漏并优化内存使用针对C#,VB.Net, 或其它.Net程序。 包含安装+注册机
  • 基于.NET4.0的MemoryMappedFile实现共享内存通信 共享内存通信可以解决跨线程、跨进程、跨EXE之间通信的问题 对于需要传输图片等引用类数据,可以通过序列化和反序列化配合共享内存实现跨进程(跨EXE)通信 共享...
  • 查看原生内存信息:jcmd process_id VM.native_memory summary jcmd <pid> VM.native_memory [summary | detail | baseline | summary.diff | detail.diff | shutdown] 1.执行命令:jcmd <pid> VM....

    目录

     

    一、Native Memory Tracking (NMT)

        是Hotspot VM用来分析VM内部内存使用情况的一个功能。我们可以利用jcmd(jdk自带)这个工具来访问NMT的数据。

    1.Native memory tracking is not enabled 打开NMT

    二、查看原生内存信息:jcmd process_id VM.native_memory summary

    1.打基线

    2.查看detail

    3.使用summary.diff来查看跟baseline对比的统计信息

    4.jcmd查看NMT报告

    5.NMT报告分析

    总结:


    一、Native Memory Tracking (NMT)

        是Hotspot VM用来分析VM内部内存使用情况的一个功能。我们可以利用jcmd(jdk自带)这个工具来访问NMT的数据。

    1.Native memory tracking is not enabled 打开NMT

    NMT必须先通过VM启动参数中打开,不过要注意的是,打开NMT会带来5%-10%的性能损耗。

    -XX:NativeMemoryTracking=[off | summary | detail]
    # off: 默认关闭
    # summary: 只统计各个分类的内存使用情况.
    # detail: Collect memory usage by individual call sites.
    例如:-XX:NativeMemoryTracking=detail

    二、查看原生内存信息:jcmd process_id VM.native_memory summary

    jcmd <pid> VM.native_memory  [summary | detail | baseline | summary.diff | detail.diff | shutdown] 

    1.打基线

    jcmd 1 VM.native_memory baseline

    2.查看detail

    jcmd <pid>  VM.native_memory detail  scale=MB
    jcmd <pid>  VM.native_memory detail 

     

    3.使用summary.diff来查看跟baseline对比的统计信息

     

    jcmd <pid> VM.native_memory summary.diff

     

    4.jcmd查看NMT报告

    jcmd <pid> VM.native_memory [summary | detail | baseline | summary.diff | detail.diff | shutdown] [scale= KB | MB | GB]
    
    # summary: 分类内存使用情况.
    # detail: 详细内存使用情况,除了summary信息之外还包含了虚拟内存使用情况。
    # baseline: 创建内存使用快照,方便和后面做对比
    # summary.diff: 和上一次baseline的summary对比
    # detail.diff: 和上一次baseline的detail对比
    # shutdown: 关闭NMT
    •  

    5.NMT报告分析

    reserved表示应用可用的内存大小
    committed表示应用正在使用的内存大小

    Total: reserved=1927465KB +66KB, committed=887589KB +66KB

    -                 Java Heap (reserved=1048576KB, committed=524288KB)
                                (mmap: reserved=1048576KB, committed=524288KB)
     
    -                     Class (reserved=387186KB, committed=89842KB)
                                (classes #15588) 已经加载的classes个数
                                (malloc=2162KB #23499)
                                (mmap: reserved=385024KB, committed=87680KB)
                   
    -                    Thread (reserved=46014KB, committed=46014KB)   
                                (thread #85)   Thread部分表示线程个数
                                (stack: reserved=45648KB, committed=45648KB)
                                (malloc=267KB #448)
                                (arena=98KB #165)
     
    -                      Code (reserved=256433KB, committed=39725KB)  表示JIT生成的或者缓存的instructions占用
                                (malloc=6833KB #9122)
                                (mmap: reserved=249600KB, committed=32892KB)
     
    -                        GC (reserved=49673KB, committed=48137KB)  目前已经占用的内存空间用于帮助GC
                                (malloc=46593KB #362)
                                (mmap: reserved=3080KB, committed=1544KB)
     
    -                  Compiler (reserved=309KB, committed=309KB)
                                (malloc=178KB #1157)
                                (arena=131KB #6)
     
    -                  Internal (reserved=71623KB +1KB, committed=71623KB +1KB) 表示命令行解析、JVMTI等占用
                                (malloc=71591KB +1KB #19791 +4)
                                (mmap: reserved=32KB, committed=32KB)
     
    -                    Symbol (reserved=22144KB, committed=22144KB)  表示诸如string table及constant pool等symbol占用
                                (malloc=18492KB #182273)
                                (arena=3652KB #1)
     
    -    Native Memory Tracking (reserved=4222KB +66KB, committed=4222KB +66KB)  表示该功能自身占用
                                (malloc=425KB +54KB #6037 +760)
                                (tracking overhead=3797KB +12KB)
     
    -               Arena Chunk (reserved=189KB, committed=189KB) 表示arena chunk占用
                                (malloc=189KB)
     
    -                   Unknown (reserved=41096KB, committed=41096KB)
                                (mmap: reserved=41096KB, committed=41096KB)

     

    总结:

     

    java8给HotSpot VM引入了Native Memory Tracking (NMT)特性,可以用于追踪JVM的内部内存使用
    
    使用-XX:NativeMemoryTracking=summary可以用于开启NMT,其中该值默认为off,
    可以设置summary、detail来开启;开启的话,大概会增加5%-10%的性能消耗;使用-XX:+UnlockDiagnosticVMOptions -XX:+PrintNMTStatistics
    可以在jvm shutdown的时候输出整体的native memory统计;
    其他的可以使用jcmd pid VM.native_memory相关命令进行查看、diff、shutdown等
    
    整个memory主要包含了Java Heap、Class、Thread、Code、GC、Compiler、Internal、Other、Symbol、Native Memory Tracking、Arena Chunk这几部分;其中reserved表示应用可用的内存大小,committed表示应用正在使用的内存大小
    

     

    展开全文
  • am-memory,driver-memory,executor-memory

    千次阅读 2019-10-17 11:12:11
    先搞清几个概念: spark 提交任务方式 spark 提交任务有两种...yarn-cluster的ApplicationMaster在任一一台NodeManager上启动,此方式ApplicationMaster包含driver,am的内存:driver.memory+driver.memoryOverhea...
  • lucene-memory-3.6.2.jar

    热门讨论 2014-05-21 15:05:22
    lucene-memory-3.6.2.jar包,需要的拿走

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,401,683
精华内容 560,673
关键字:

memory