postgresql 查询序列_新型硬件GPU在PostgreSQL的应用

译者: 朱君鹏,陈河堆

作者简介

Naju Mancheril,来自卡耐基梅隆大学。这是一篇介绍在PostgreSQL中应用新型硬件GPU提升排序性能的论文,是当前热门的数据库前沿技术研究领域。原论文名称为《GPU-based Sorting in PostgreSQL》。

译者简介

朱君鹏华东师范大学博士研究生,个人兴趣主要集中在:新型硬件(GPU、RDMA、FPGA)等在数据库中的应用,架构设计与并行计算。

陈河堆,中兴通讯数据库平台负责人,曾参与和主导公司自研高性能内存数据库、分布式数据库和分布式缓存等系统的开发和设计,目前致力于PostgreSQL数据库的研究和推广。

1. 概述

在过去十年中,每个微处理器内核的晶体管数量有所增加,但复杂性的增加仅导致应用性能的适度增加。大多数性能改进可以追溯到技术扩展的更快时钟速率。虽然更复杂的内核提供更高的单线程性能,但它们通常不适合具有大量独立线程的应用程序。在后一种情况下,具有多个简单独立内核的多处理器可提供最佳性能[1]。本文不寻求解决哪种级别的复杂性更适合数据库管理系统。相反,我们探索异构处理环境提供的优势。特别是,虽然在通用CPU上执行我们的数据库管理系统,但我们分析了使用一个GPU来辅助排序操作可能提供的性能改进。

现代GPU(图形处理单元)的结构与通用CPU非常不同。GPU针对一系列操作(比如纹理映射)进行了优化,这在CPU中是没有等效硬件支持的。它们的内存子系统也不同,因为除了板载视频内存之外,GPU还必须管理到系统RAM的高速接口。然而,最令人吃惊的区别在于对并行性的硬件支持水平。虽然现代GPU的时钟频率仅为400 MHz,但它可以有多达20个独立的流水线。每个时钟周期,有大量指令可以执行完毕[2]。

由于这种并行性,现代GPUS在原始FLOPS(每秒浮点运算)方面甚至超过了高端CPU。最近,在利用这种处理能力并用它来解决通用计算中出现的复杂问题方面已经做了很多工作[3]。一个这样的问题是排序。排序是现代数据库和数据挖掘系统中主要延迟的原因。这些系统通常简化为使用基于CPU的内存快速排序。在本文中,我们展示如果允许这些系统访问图形处理器,他们可以利用特别适合现代GPU功能的快速并行排序算法。

北卡罗来纳大学教堂山分校的GPUSort项目致力于设计和实现基于GPU的高效排序算法。我们使用的GPUSort实现通过使用OpenGL纹理映射操作将一个bitonic排序网络映射到GPU。排序算法还通过使用高速缓存有效的内存访问模式充分利用了图形卡的内存带宽。图1显示了使用一个第一代旧NVIDIA GPU [4]在3.4 GHz奔腾4处理器系统上运行的GPUSort击败qsort()。

717fa9baf36d82db4b9d41818127d44a.png

图1 原始GPUSort和原始qsort() [4]

我们通过将其与PostgreSQL数据库管理系统集成来探索GPUSort提供的改进。具体来说,我们使用它来实现用于处理SQL语句中的ORDER BY子句的键指针排序。我们发现由于将元组传递给图形卡的通信开销,qsort()仍然是排序小关系的更快选择。但是,当关系达到中等大小(大约1MB)时,GPUSort表现更好。

本文的其余部分的结构如下。第2节简要介绍了Bitonic排序网络。第3节讨论了我们修改过的PostgreSQL系统的体系结构。第4节包含我们实验评估的设置。第5节包含我们的实验结果和分析。最后,第6节包含我们的结论和未来工作的可能领域。

2. Bitonic排序

Bitonic排序(或bitonic归并排序)[5]是一种利用排序网络的快速排序算法。排序网络[6]是一个特殊的基于比较的并行排序过程,其中比较序列不依赖于数据[7] [8] [9]。这使得排序网络成为理想的并行化功能,甚至可能在硬件中实现。

假设有一个序列a = a0,....,a n1,其中ai∈{0,1}, i = 0,...,n−1,它称为0-1序列。如果在0和1比特系列之间最多包含两次变化,则该0-1序列称为bitonic。即如果存在子序列长度k,m∈{1,... ,n},使得

    a0, . . . , ak−1 = 0, ak, . . . , am1 = 1, am, . . . , an1 = 0

    a0, . . . , ak1 = 1, ak, . . . , am1 = 0, am, . . . , an1 = 1

Bitonic排序网络有两个主要组成部分:比较器网络和归并网络。这些组件是递归定义的。如果Bn是一个能对n位数进行排序的比较器网络,则有:

        Bn(a) = b0, . . . , bn/21 c0, . . . , cn/21 

其中,对于i,j∈{1 ,...,n / 2 - 1},有bi≤cj,而且,b0 ,... ,bn/2-1和c0 ,... ,cn/2-1,每个都是bitonic。归并网络将这两个有序的bitonic序列组合成一个。现在对n位进行排序成为一个标准的分而治之算法,包括拆分和排序阶段,然后跟随一个归并阶段。

8ebe8c8213553076ba5f2c8fb11e29c1.png

图2 Bitonic 排序[10]

每个排序和归并迭代称为一个阶段。通过使用n个独立处理器的阵列,bitonic排序允许我们在O(log n)阶段内对n个元素进行排序,且每个阶段只需O(log n)个步骤。总运行时间为O(log2 n),远远优于quicksort [11]提供的O(n log n)时间。

GPUSort使用OpenGL纹理映射函数将32位浮点比较器网络映射到我们图形处理器的20条流水线上。因此,我们可以在每个400 MHz周期中执行完大约20个比较指令,与之鲜明对比是,每个周期3.0GHz CPU只能执行完2-3个指令。

3.数据库体系结构

PostgreSQL中的排序操作是使用tuplesort模块实现的。尽管所有数据库操作符都具有迭代器风格的接口(open,next,close),但正确排序需要访问所有输入元组。因此,tuplesort接口要求sort操作符代码从其输入流中对每个元组调用puttuple(),然后调用performsort()进行实际排序,最后在每次next()调用时调用gettuple(),直到每个元组都被有序获取。

peformsort()函数可以以两种方式之一工作。对于小数据集(小于1MB),它构造一个元组指针的纯内存数组,定义一个比较器函数来对两个元组指针进行排序,然后调用libC 的qsort()函数。对于较大的数据集,它使用带堆排序的外部排序来构建有序的执行系列。

图3显示了我们所做修改的高层次描述。一旦我们能够从元组指针中抽取浮点键,我们就能够构造自己的浮点数偶对数组,并将这个纯内存数组直接传递给GPUSort代码。完成之后,使用有序的键指针数组将原始的元组数组置换为有序顺序。

0898c57392e054ce7c2cb87da66a7158.png

图3 PostgreSQL排序体系架构

尽管SQL将FLOAT定义为4字节浮点值,但PostgreSQL内部使用64位(双)数据类型来表示它。只可惜GPUSort当前只支持16位和32位浮点数,否则这不算什么问题。出于这个原因,在应用GPUSort之前,我们必须将每个double值舍入到最接近的float值。此舍入过程不会更改结果元组的集合,因为在我们的工作负载中使用的元组不会使用超过几位数的精度。反而,在评估最终实现时,应牢记舍入的代价。完全采用GPUSort的任何系统要么使用32位浮点数,要么获取支持64位键值的GPUSort版本。

另一个问题是我们的GPUSort版本似乎是专门为32位机器设计的。因此,即使我们将FLOAT32指针偶对的数组传递给排序例程,OpenGL代码也假设每个偶对的总大小为8个字节。我们通过传入FLOAT32偏移偶对数组来解决这个问题:我们传递了每个元素在元组数组中的偏移量,而不是每个元素的绝对地址。由于偏移量是32位数,我们仍然可以对最多40亿个元组的数组进行排序,但我们希望在将来的工作中消除这种限制。

4实验设置

4.1 硬件

所有的开发和评估都是在具有2048KB缓存和超线程的3.0GHz Intel(R)Pentium(R)4 CPU上完成的。系统配备1GB主内存。使用的显卡是eVGA Geforce 7800GT,配备256MB RAM。核心GPU速度为400 MHz,板载内存运行速度为500 MHz。该卡使用x16 PCI-Express接口,最大额定内存带宽为54.4GB /秒[2]。

4.2 软件

我们的排序是来自北卡罗来纳大学教堂山分校的GPUSort项目的GPUSort 1.0。我们将它集成到PostgreSQL 8.2devel中。所有评估都在Fedora Core第4版上完成,Linux内核版本为2.6.11-1.1369_FC4smp,针对x86_64进行了优化。

4.3 工作负载

我们使用一个微基准测试风格的评估,因为我们只关心测量排序操作符的性能。实验使用如下表模式:

TABLE vals(x FLOAT, y FLOAT)

我们在这个表中填充了一百万个元组,这些元组在0.0到100.0之间随机均匀生成。我们所有的查询都来自以下模板:

SELECT * FROM vals

WHERE y < y0

ORDER BY y

这个简单的查询总是产生如图4所示的双运算符查询计划。

f2105144c5e6e68165946b37b444605c.png

                   图4 微基准测试查询计划

由于基表中的元组是随机均匀生成的,我们可以通过改变y0的值来控制SCAN运算符的选择性。例如,通过将y0设置为10.0,我们可以执行一次对(10.0 / 100.0)·100万= 100,000个元组的排序。

在我们的实验中,我们改变了关系大小以及图形卡上GPUSort代码使用的视频内存量。另一个可能调节的参数是元组大小。但是,这不会影响排序成本,因为PostgreSQL实现了键指针排序。无论每个元组的大小如何,当我们执行比较和交换时,我们只会移动浮点数和字大小的指针(或者对于GPUSort来说是一个32位的偏移)。

5. 实验结果

5.1 大输入

我们比较了三种不同排序算法的执行时间:默认的PostgreSQL外部排序,PostgreSQL内部排序和GPUSort。图5显示了这三种算法在大输入规模下的性能。“堆排序”是PostgreSQL外部排序算法。它使用堆排序来创建每个1MB的有序执行系列,然后将它们归并在一起。“qsort”表示内部排序算法,它实际上只是对libC qsort()函数的调用。出于测量目的,我们将qsort使用的内存量增加到1GB。GPUSort 256MB显示使用256 MB视频卡的GPUSort运行时间。

需要注意的一点是,“堆排序”的执行时间不随输入大小单调增加。由于该算法基于分而治之思想,因此当输入可以被均分多次时,它将表现得更好。虽然在图5中很难看得出来,但GPUSort也表现出这种行为特征。这在图6中应该看得更清楚,它显示了GPUSort如何随着更大输入而按比例增长1

6e5585f68014c2c2f40478338aadb41b.png

图5 ORDER BY子句执行时间

a8d507e2d32ccfd8c7eacf1a26643ae9.png

图6 GPUSort ORDER BY子句执行时间

每当元组数量跨过一个2的幂次方时,我们就会看到排序时间的一次下降。我们在50万、100万、200万和400万个元组时分别看到了这个现象。对420万个元组进行排序所花费的时间比对400万个元组进行排序所花费的时间要少。此行为实际上是GPUSort库的实现方式。在应用纹理映射例程之前,GPUSort会将元组编组为内部矩阵。当前实现不会对完全在GPU上对数组进行排序,它将产生非2的幂次方大小的矩阵。相反,它采用比输入数组尺寸小的2的最大幂,在GPU上对结果矩阵进行排序,使用qsort()对剩余数据进行排序,最后将两个流归并在一起。由于涉及到额外的CPU使用开销,代码运行在非2的幂次方大小的数组上执行得更慢[4]。

好消息是即使我们可能会看到执行时间的这种变化,但是,当数据集变大时,GPUSort总是比qsort()快。即使查询优化器必须决定使用哪种排序算法,也无需专门处理这些2的幂次方问题。事实上,对于大型(大于1MB)数据集,GPUSort的执行速度始终是内部快速排序的4倍。

5.2 小输入

我们已经看到GPUSort的性能取决于它需要多少CPU支持。尽管图5显示GPUSort的性能优于基于CPU的替代方案,但这些测量是通过大输入来完成的,这里的执行时间主要由排序时间来决定。情况并非总是如此。我们可以将应用程序用于执行GPUSort的总时间分为四个部分:

        Tsort = Tarray_build + Tnetwork_build + Ttransfer + TGPU + TCPU

Tsort是总排序时间,Tarray_build是使用CPU构建键偏移数组所需的时间,Tnetwork_build是在GPU上构建一个bitonic排序网络所需的时间,Ttransf er是将数据传输到GPU所需的时间。TGPU是对显卡进行排序所需的时间,而TCPU是qsort()剩余数据和归并两个有序流所需的任何额外时间。

68bf65613eba02489c1df2e0fcd4c55f.png

                   BY子句处理时间

创建单独的键指针数组+Tarray_build+创建排序网络+Tnetwork_build+将元组传递到图形卡Ttransfer的开销对于排序小关系而言可能太高。图7展示了这种情况。当要排序的元组数量小于10万时,qsort()实际上是更快的选项。

5.3 显存大小

GPUSort必须在显卡的视频内存中保留空间,以存储将要被排序的矩阵。通过改变GPUSort对总视频内存大小的估算,我们可以控制它生成的矩阵的大小。我们很想知道当GPUSort拥有处理功能较弱的图形处理器时的性能表现。图8显示了此功能伸缩时的结果。

d4b57e89b85f92ff6a059dec36b30e38.png

图8 改变视频内存

该图表中的奇怪结果是256MB显卡表现最差。256MB是我们使用的视频图形卡的总内存容量。最初,我们认为这种糟糕的性能可能是视频内存和系统RAM之间抖动的结果。毕竟,PostgreSQL必须与XWindows和其他可能正在运行的应用程序共享显卡。然而,通过运行更多测试,我们可以找到更简单的解释。回想一下GPUSort的执行时间分解:

        Tsort = Tarray_build + Tnetwork_build + Ttransfer + TGPU + TCPU

事实证明,Tnetwork_build根据GPUSort将使用的视频内存量成比例进行缩放。为了构建我们的排序网络,我们必须在显卡上分配内存,决定在哪里放置我们的矩阵,并承担在系统RAM和显卡之间建立未来传输所涉及的任何开销。事实证明,没有必要为每次排序构建一个新的排序网络。我们可以“预先计算”卡上的排序网络,并在每次排序中重复使用它。其结果,Tnetwork_build被摊销了,而我们看到了更合理的执行时间:

9748661469d0cad97a450151a2a0e660.png

                  图9 改变视频内存与重用排序网络

图9显示,对于大型数据集,GPUSort非常之快,以至于它实际并在乎GPU可以访问多少视频内存。其性能仅受GPU速度和可用于将数据从系统RAM传输到视频RAM的带宽的限制。根据这些参数测量性能是未来工作的主题。

6. 结论

本文通过将其与PostgreSQL数据库管理系统集成,探讨了GPUSort(一种基于GPU的快速排序算法)所提供的改进。具体来说,它被用来实现用于处理SQL语法ORDER BY子句的键指针排序。我们发现由于将元组传输到显卡所涉及的开销,qsort()仍然是较小关系的更快选择。然而,当关系的大小变为1 MB级别时,GPUSort会更快。

现代GPU不会取代通用CPU,但其独特的并行流水线设计给予它们巨大潜力,用于提升计算和内存受限程序的性能。即使是64MB显卡(其售价低于100美元),也可以比传统的基于CPU的qsort()提供很大改进。

GPU提供的好处只会随着每张卡内流水线的速度和数量而增加。随着PCI Express的出现,总线传输变得越来越不成为瓶颈,这种技术提供了两倍于旧AGP-8x接口的独立传输通道。这些进步促成了许多项目的创建,特别是GPGPU项目,他们完全致力于设计和实现用于通用应用软件编码的GPU协处理器库。虽然基于图形库的应用程序可能更难开发,但它们最终会胜出:这些库提供的性能提升将超过复杂性的增加。

数据库系统不是唯一在不同执行阶段具有非常不同资源需求的应用程序。在“正常”执行期间,存在大量指令级并行性。为了执行这样的程序,一个多发的超标量CPU提供了最佳性能。但是,当应用程序需要执行一些计算密集型操作(如排序)时,大量独立流水线提供了最佳性能。最后,内核复杂性的最佳选择实际上可能是“以上全部”:同时具有高和低复杂度内核的异构芯片多处理器,可以在程序执行的不同阶段分别激活[1]。

引用

[1] R. Kumar, D. Tullsen, N. Jouppi, and P. Ranganathan. Heterogeneous chip multiprocessors. IEEE Computer, 38, No. 11:32–38, 2005.

[2] NVIDIA Corporation. NVIDIA GeForce 7800 GPUs Specifications.

[3] GPGPU Project. http://www.gpgpu.org.

[4] GPUSort Project. GPUSort Documentation.

[5] K.E. Batcher. Sorting networks and their applications. volume 32, pages 307–314, 1968.

[6] T.H. Cormen, C.E. Leiserson, and R.L. Rivest. Introduction to Algorithms. MIT Press / McGraw-Hill, Cambridge, Massachusetts, 1990.

[7] C.D. Thompson and H.T. Kung. Sorting on a meshconnected parallel computer. Communications of the ACM, 20 4:263–271, 1977.

[8] H.W. Lang, M. Schimmler, H. Schmeck, and H. Schroder. Systolic sorting on a mesh-connected network. IEEE Transactions on Computers, C-34, 7:652–658, 1985.

[9] C.P. Schnorr and A. Shamir. An optimal sorting algorithm for mesh-connected computers. pages 255–261, 1986.

[10] Institut fur Medien Informatik und Technische Informatik. Sequentielle und parallele Sortierverfahren: Bitonic Sort.

[11] Randima Fernando. GPU Gems: Programming Techniques, Tips, and Tricks for Real-Time Graphics. Pearson Education, Boston, Massachusetts, 2003.

文章链接:https://pdfs.semanticscholar.org/869f/beb4db447174d4c6a475e942a2607465a410.pdf

a46b109aa9d69888e2c14c04670b8324.png

PostgreSQL中文社区欢迎广大技术人员投稿

投稿邮箱:press@postgres.cn

93d5cfc10dceecd9cd7a77d66173c049.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
由于内存数据库具有比基于磁盘的数据库更高的查询响应速度和并发度,其被广泛应用于银行、证券交易所和在线购物等数据量庞大并且实时性要求高的商业领域。索引能够有效降低数据的搜索空间、提高内存数据库的查询效率,然而当前它却受到性能和效率的挑战。 基于图形处理器的通用计算(GPGPU)在多个领域具有重要的研究价值和应用前景,也是当前研究的热点。目前图形处理器(GPU)上索引技术的研究已有一定的相关成果,然而这些研究成果存在着诸如:并行算法未充分利用硬件的资源、并行度不高,算法缺乏可扩展性且不能解决索引数据的更新等问题。因此,本文以如何充分利用 GPU硬件资源、最大限度地提高内存数据库索引的操作性能为主要研究内容,在相关研究的基础上,本文主要做了以下工作: 1. 对目前内存数据库索引技术的研究成果进行总结归纳,并且对 GPU硬件特点和编程技术做了相关综述。 2. 提出一种基于 GPU T-树索引的并行计算方案,该方案通过分析 T-树的节点间的父子关系,在 GPU 上实现对 T-树的最大并行度构建。设计在 GPU 上 T-树索引数据可任意伸缩的动态数组,解决 GPU 上尚无动态分配显存空间的问题;通过对各种构建 T-树方案的理论和实验分析,提出的并行建树方案较传统的建树方案,在操作效率和空间利用率上均有明显的性能优势。为解决 CUDA 程序数据传输的瓶颈问题,通过页锁定内存的方式提高 CPU 和 GPU 间的数据传输速率;为适应未来硬件发展的需求,对算法的可扩展性进行相关研究;为验证方案的正确性,提出基于 GPU T-树的遍历算法; 为验证提出的并行方案的有效性,进行相关的实验论证。 3. 为加速多维数据的操作性能,提出一种基于 GPU 多维线性哈希索引的并行处理方案。该方案通过对传统哈希索引数据结构的扩展,利用 2 层的数据结构可实现哈希表在 GPU 上的任意收缩,从而解决多维数据在 GPU 上无法有效更新的问题。在哈希表的记录并行批量插入算法中,采用并行分裂哈希桶的方式可加速哈希表分裂的处理 速度,从而提高了插入的效率;设计一个灵活的溢出桶管理机制,可提高多维哈希索引在 GPU 上的存储空间利用率;对提出的记录并行批量插入方案进行算法时间和空间复杂度的分析,并与传统的 CPU 算法进行相关对比;在各种硬件平台上对多维线性哈希索引记录的并行批量插入、批量删除和查询的操作性能进行相关的实验论证。 4. 提出一种基于 GPU 缓存敏感 CSB+-树索引的无锁并行处理方案,该方案通过对传统的 CSB+-树的结构改进,可实现 CSB+-树的索引数据在 GPU 上动态更新。在 GPU上提出基于树层和基于节点索引键 CSB+-树两种并行构建算法,其中后者可实现对CSB+-树的最大并行度构建;通过在 CSB+-树的内部节点添加填充位的方式,可减少GPU 线程块里的线程分支数,从而提高 CSB+-树的查询性能;通过对 CSB+-树的查询算法使用共享存储器的可行性分析,指出传统的缓存敏感技术的思想在复杂的 GPU 内存框架中并不适合使用。为验证提出的并行方案的有效性,在多个硬件平台上进行相关的实验论证。 5.在 GPU 平台上提出一种 BD-树索引的并行计算方案,该方案通过修改传统 BD-树的哈希函数,可实现对 BD-树索引的并行处理。通过对传统 BD-树的数据结构改进,可实现 BD-树索引数据在 GPU 上的更新操作;通过分析 BD-树的树形结构,可实现基于内部节点键的并行度方式构建 BD-树;通过增加额外的空间开销,减少 GPU 原子函数的调用次数,可显著提高 BD-树哈希表的数据插入效率;对 BD-树并行构建算法进行空间复杂度的分析,与传统的构建算法相比,提出算法的空间利用率明显得到提高。同样,为验证提出方案的有效性,进行相关的实验论证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值