精华内容
下载资源
问答
  • 数据库调优

    2020-03-11 10:22:33
    接下来问题是如何对MySQL进行调优,怎么优化SQL以及MySQL配置,才能发挥MySQL性能? 一.SQL语句优化 对SQL语句优化主要体现在对索引使用 书写SQL时候要注意,某些特殊语句是没有办法使用索引。 ...

    前几篇我们已经完成了数据库的表设计。

    新零售平台的数据库设计(一)

    新零售平台的数据库设计(二)

    新零售平台数据库的设计(三)

    接下来问题是如何对MySQL进行调优,怎么优化SQL以及MySQL的配置,才能发挥MySQL的性能?

    一.SQL语句的优化

    对SQL语句的优化主要体现在对索引的使用
    书写SQL的时候要注意,某些特殊的语句是没有办法使用索引的。

    1. 使用模糊查询的时候,%如果写在前面,是没有办法通过索引检索的。
    2. Order By 语句如果是对索引的属性排序,速度会很快。
    3. 使用is null 或者 is not null ,MySQL查询的时候会放弃使用索引,而是使用遍历检索。可以设置一些逻辑上不可能出现的值来表示NULL
    4. 因为索引是按照大小排列的,因此不要使用!=这样的符号来进行索引,可以使用同时满足小于和大于的条件来检索。
    5. 少使用OR运算符,这样第一个OR条件可能会使用索引,但是第二个是不会使用索引检索的,可以通过UNION ALL 把两个检索条件合并。(最左分配原则)
    6. 避免运算符出现在表达式的左侧,这样同样不会使用索引检索。

    二.MySQL的参数调优

    在MySQL数据库中,我们可以通过设置参数来优化MySQL的配置,主要的形式是修改my.cnf,然后重启MySQL。

    MySQL的重要参数有以下几个:

    1. max-connections 最大连接数 。

    • 表示MySQL的最大并发连接数,默认值是151,MySQL允许的最大连接上限是16000多。
    • 实际连接数是最大连接数的85%比较合适。
    • 注意不要盲目地调大max_connections,因为每一个连接都会占用一个缓冲池。
     		- show variable like 'max_connection'    用于查看最大连接数值
    
    		- show status like 'max_used_connections'   用于查看曾经出现过的最大连接数
    

    2. back_log 请求堆栈

    • 连接数到达最大连接数之后,数据库会把多余的请求放在堆栈中,back_log的值就是指堆栈中允许的最多请求数量,默认值是50。
    • back_log为max_connections的30%比较恰当。

    3. innodb_thread_concurrency 并发线程数

    • 指MySQL允许的最大线程数量,默认值为0,表示不设上限。
    • 因为线程数变多之后,线程的调度同样要耗费大量的资源。
    • 最佳值是CPU核心的2倍。

    4. innodb_buffer_pool_size 指 InnoDB的缓存容量

    • 数据库的查询缓存是缓存select结果集,当某个数据删改之后,会造成大面积的缓存失效。
    • 与数据库的查询缓存不同,innoDB不会把查询的结果集缓存在内存上,而是缓存一部分数据以及索引,提升查询的效率。
    • 默认值为128M,最佳容量是内存的70%。

    三.查看慢查询日志

    MySQL提供了慢查询日志,帮我们记录SQL中花费时间超过规定的时间的语句。

    show variables like ‘slow_query%’

    可以查询出当前的慢查询日志是否开启,以及日志的存放目录。

    同样的在my.cnf中去修改参数

    slow_query_log = on 开启慢日志

    log_query_time =1 把规定的时间设置为1S

    然后按照之前的慢查询日志的目录,我们就可以看到执行较慢的语句的具体信息。

    可以通过explain去分析执行较慢语句的执行情况。

    展开全文
  • 数据库调优,其中一个重点就是应用程序SQL调优。而应用程序调优范围比较广,可以从调整业务角度做调优,也可以从重构代码角度调优。但是无论用什么办法调优,都必须要先读懂SQL执行计划,了解应用程序...
  • 作者:吴毅 王远立 TiKV 底层使用了 RocksDB 作为存储...如果有一个自动 tuning 的方案就可以大大减少调优的人力成本,同时也可能在调优的过程中,发现一些人工想不到的信息。我们从 AutoML 中得到启发,希望能用 A...

    作者:吴毅 王远立

    TiKV 底层使用了 RocksDB 作为存储引擎,然而 RocksDB 配置选项很多,很多情况下只能通过反复测试或者依靠经验来调优,甚至连 RocksDB 的开发者都自嘲,他们没办法弄清楚每个参数调整对性能的影响。如果有一个自动 tuning 的方案就可以大大减少调优的人力成本,同时也可能在调优的过程中,发现一些人工想不到的信息。我们从 AutoML 中得到启发,希望能用 Automated Hyper-parameter Tuning 中的一些方法来对数据库参数进行自动调优。

    常用的 Automated Hyper-parameter Tuning 方式大体上有以下三种:

    1. 随机搜索,或者说叫启发式搜索。包括 GridSearch 和 RandomSearch。这种方法的改进空间主要体现在使用不同的采样方法生成配置,但本质上仍然是随机试验不同的配置,没有根据跑出来的结果来反馈指导采样过程,效率比较低。

    2. Multi-armed Bandit。这种方法综合考虑了“探索”和“利用”两个问题,既可以配置更多资源(也就是采样机会)给搜索空间中效果更优的一部分,也会考虑尝试尽量多的可能性。Bandit 结合贝叶斯优化,就构成了传统的 AutoML 的核心。

    3. 深度强化学习。强化学习在 AutoML 中最著名的应用就是 NAS,用于自动生成神经网络结构。另外它在 深度学习参数调优 中也有应用。它的优点是从“从数据中学习”转变为“从动作中学习”(比如 knob 中的 cache size 从小调到大),既可以从性能好的样本中学习,也可以从性能坏的样本中学习。但强化学习的坑也比较多,体现在训练可能比较困难,有时结果比较难复现。

    目前学术界针对 auto-tune 数据库的研究也有很多,采用的方法大多集中在后面两种。其中一个比较有名的研究是 OtterTune我们受 OtterTune 的启发,开发了 AutoTiKV,一个用于对 TiKV 数据库进行自动调优的工具。项目启动三个月以来,AutoTiKV 在 TiKV 内部测试和调参的环节起到了较好的效果,有了一个很好的开始。后续我们还会针对生产环境上的一些特点,对它进行继续探索和完善。

    项目地址:https://github.com/tikv/auto-tikv

    设计目标

    整个调优过程大致如下图:

    图 1 调优过程

    整个过程会循环跑 200 个 round(可以用户自定义),或者也可以定义成到结果收敛为止。

    AutoTiKV 支持在修改参数之后重启 TiKV(如果不需要也可以选择不重启)。需要调节的参数和需要查看的 metric 可以在 controller.py 里声明。

    一开始的 10 轮(具体大小可以调节)是用随机生成的 knob 去 benchmark,以便收集初始数据集。之后的都是用 ML 模型推荐的参数去 benchmark。

    ML 模型

    AutoTiKV 使用了和 OtterTune 一样的高斯过程回归(Gaussian Process Regression,以下简称 GP)来推荐新的 knob[1],它是基于高斯分布的一种非参数模型。高斯过程回归的好处是:

    1. 和神经网络之类的方法相比,GP 属于无参数模型,算法计算量相对较低,而且在训练样本很少的情况下表现比 NN 更好。

    2. 它能估计样本的分布情况,即 X 的均值 m(X) 和标准差 s(X)。若 X 周围的数据不多,则它被估计出的标准差 s(X) 会偏大(表示这个样本 X 和其他数据点的差异大)。直观的理解是若数据不多,则不确定性会大,体现在标准差偏大。反之,数据足够时,不确定性减少,标准差会偏小。这个特性后面会用到。

    但 GP 本身其实只能估计样本的分布,为了得到最终的预测值,我们需要把它应用到贝叶斯优化(Bayesian Optimization)中。贝叶斯优化算法大致可分为两步:

    1. 通过 GP 估计出函数的分布情况。

    2. 通过采集函数(Acquisition Function)指导下一步的采样(也就是给出推荐值)。

    采集函数(Acquisition Function)的作用是:在寻找新的推荐值的时候,平衡探索(exploration)和利用(exploitation)两个性质:

    • exploration:在目前数据量较少的未知区域探索新的点。
    • exploitation:对于数据量足够多的已知区域,利用这些数据训练模型进行估计,找出最优值。

    在推荐的过程中,需要平衡上述两种指标。exploitation 过多会导致结果陷入局部最优值(重复推荐目前已知的最好的点,但可能还有更好的点没被发现),而 exploration 过多又会导致搜索效率太低(一直在探索新区域,而没有对当前比较好的区域进行深入尝试)。而平衡二者的核心思想是:当数据足够多时,利用现有的数据推荐;当缺少数据时,我们在点最少的区域进行探索,探索最未知的区域能给我们最大的信息量。

    贝叶斯优化的第二步就可以帮我们实现这一思想。前面提到 GP 可以帮我们估计 X 的均值 m(X) 和标准差 s(X),其中均值 m(x) 可以作为 exploitation 的表征值,而标准差 s(x) 可以作为 exploration 的表征值。这样就可以用贝叶斯优化方法来求解了。

    使用置信区间上界(Upper Confidence Bound)作为采集函数。假设我们需要找 X 使 Y 值尽可能大,则 U(X) = m(X) + k*s(X),其中 k > 0 是可调的系数。我们只要找 X 使 U(X) 尽可能大即可。

    • U(X) 大,则可能 m(X) 大,也可能 s(X) 大。

    • s(X) 大,则说明 X 周围数据不多,需要探索未知区域新的点。

    • m(X) 大,说明估计的 Y 值均值大, 则需要利用已知数据找到效果好的点。

    • 其中系数 k 影响着探索和利用的比例,k 越大,越鼓励探索新的区域。

    在具体实现中,一开始随机生成若干个 candidate knobs,然后用上述模型计算出它们的 U(X),找出 U(X) 最大的那一个作为本次推荐的结果。

    数据库参数

    workload

    测试中我们使用了 YCSB 来模拟 write heavy、long range scan、short range scan 和 point-lookup 四种典型 workload。数据库大小都是 80GB。[2]

    knobs

    我们试验了如下参数:

    Options Expected behavior valid range/value set
    write-buffer-size point-lookup, range-scan: larger the better [64MB, 1GB]
    max-bytes-for-level-base point-lookup, range-scan: larger the better [512MB, 4GB]
    target-file-size-base point-lookup, range-scan: larger the better {8M, 16M, 32M, 64M, 128M}
    disable-auto-compactions write-heavy: turn on is better point-lookup, range-scan: turn off is better {1, 0}
    block-size point-lookup: smaller the better, range-scan: larger the better {4k,8k,16k,32k,64k}
    bloom-filter-bits-per-key point-lookup, range-scan: larger the better [5,10,15,20]
    optimize-filters-for-hits point-lookup, range-scan: turn off is better {1,0}

    这些参数的含义如下:

    • block-size:RocksDB 会将数据存放在 data block 里面,block-size 设置这些 block 的大小,当需要访问某一个 key 的时候,RocksDB 需要读取这个 key 所在的整个 block。对于点查,更大的 block 会增加读放大,影响性能,但是对于范围查询,更大的 block 能够更有效的利用磁盘带宽。

    • disable-auto-compactions:定义是否关闭 compaction。compaction 会占用磁盘带宽,影响写入速度。但如果 LSM 得不到 compact, level0 文件会累积,影响读性能。其实本身 compaction 也是一个有趣的 auto-tuning 的方向

    • write-buffer-size:单个 memtable 的大小限制(最大值)。理论上说更大的 memtable 会增加二分查找插入位置的消耗,但是之前的初步试验发现这个选项对 writeheavy 影响并不明显。

    • max-bytes-for-level-base:LSM tree 里面 level1 的总大小。在数据量固定的情况下,这个值更大意味着其实 LSM 的层数更小,对读有利。

    • target-file-size-base:假设 target-file-size-multiplier=1 的情况下,这个选项设置的是每个 SST 文件的大小。这个值偏小的话意味着 SST 文件更多,会影响读性能。

    • bloom-filter-bits-per-key:设置 Bloom Filter 的位数。对于读操作这一项越大越好。

    • optimize-filters-for-hits:True 表示关闭 LSM 最底层的 bloom filter。这个选项主要是因为最底层的 bloom filter 总大小比较大,比较占用 block cache 空间。如果已知查询的 key 一定在数据库中存,最底层 bloom filter 其实是没有作用的。

    metrics

    我们选择了如下几个 metrics 作为优化指标。

    • throughput:根据具体 workload 不同又分为 write throughput、get throughput、scan throughput

    • latency:根据具体 workload 不同又分为 write latency、get latency、scan latency

    • store_size

    • compaction_cpu

    其中 throughput 和 latency 通过 go-ycsb 的输出结果获得,store_size 和 compaction_cpu 通过 tikv-ctl 获得。

    实验测试结果

    测试平台

    AMD Ryzen5-2600 (6C12T),32GB RAM,512GB NVME SSD,Ubuntu 18.04,tidb-ansible 用的 master 版本。

    所有的实验都是前 10 轮用随机生成的配置,后面使用模型推荐的配置:

    workload=writeheavy  knobs={disable-auto-compactions, block-size}  metric=write_latency
    

    实验效果如下:

    这个实验中推荐结果是启用 compaction、同时 block size 设为 4KB。

    虽然一般来说写入时需要关闭 compaction 以提升性能,但分析后发现由于 TiKV 使用了 Percolator 进行分布式事务,写流程也涉及读操作(写冲突检测),所以关闭 compaction 也导致写入性能下降。同理更小的 block size 提高点查性能,对 TiKV 的写流程性能也有提升。

    接下来用 point lookup 这一纯读取的 workload 进行了试验:

    workload=pntlookup80  knobs={'bloom-filter-bits-per-key', 'optimize-filters-for-hits', 'block-size', 'disable-auto-compactions'}  metric=get_latency
    

    实验效果如下:

    推荐结果为:bloom-filter-bits-per-key20,block-size4K,不 disable auto compaction。而 optimize-filters-for-hits 是否启用影响不大(所以会出现这一项的推荐结果一直在摇摆的情况)。

    推荐的结果都挺符合预期的。关于 optimize-filter 这一项,应该是试验里面 block cache 足够大,所以 bloom filter 大小对 cache 性能影响不大;而且我们是设置 default CF 相应的选项(关于 TiKV 中对 RocksDB CF 的使用,可以参考 《TiKV 是如何存取数据的》),而对于 TiKV 来说查询 default CF 之前我们已经确定相应的 key 肯定存在,所以是否有 filter 并没有影响。之后的试验中我们会设置 writeCF 中的 optimize-filters-for-hits(defaultCF 的这一项默认就是 0 了);然后分别设置 defaultCF 和 writeCF 中的 bloom-filter-bits-per-key,把它们作为两个 knob。

    为了能尽量测出来 bloom filter 的效果,除了上述改动之外,我们把 workload 也改了一下:把 run phase 的 recordcount 设成 load phase 的两倍大,这样强制有一半的查找对应的 key 不存在,这样应该会测出来 write CF 的 optimize-filters-for-hits 必须关闭。改完之后的 workload 如下:

    workload=pntlookup80  knobs={rocksdb.writecf.bloom-filter-bits-per-key,  rocksdb.defaultcf.bloom-filter-bits-per-key, rocksdb.writecf.optimize-filters-for-hits,  rocksdb.defaultcf.block-size, rocksdb.defaultcf.disable-auto-compactions}  metric=get_throughput
    

    这次的实验效果如下(发现一个很出乎意料的现象):

    测出来发现推荐配置基本集中在以下两种:

    • {3,1,1,0,0}

      rocksdb.writecf.bloom-filter-bits-per-key [‘rocksdb’, ‘writecf’] bloom-filter-bits-per-key 20

      rocksdb.defaultcf.bloom-filter-bits-per-key [‘rocksdb’, ‘defaultcf’] bloom-filter-bits-per-key 10

      rocksdb.writecf.optimize-filters-for-hits [‘rocksdb’, ‘writecf’] optimize-filters-for-hits True

      rocksdb.defaultcf.block-size [‘rocksdb’, ‘defaultcf’] block-size 4KB

      rocksdb.defaultcf.disable-auto-compactions [‘rocksdb’, ‘defaultcf’] disable-auto-compactions False

    • {2,2,0,0,0}

      rocksdb.writecf.bloom-filter-bits-per-key [‘rocksdb’, ‘writecf’] bloom-filter-bits-per-key 15

      rocksdb.defaultcf.bloom-filter-bits-per-key [‘rocksdb’, ‘defaultcf’] bloom-filter-bits-per-key 15

      rocksdb.writecf.optimize-filters-for-hits [‘rocksdb’, ‘writecf’] optimize-filters-for-hits False

      rocksdb.defaultcf.block-size [‘rocksdb’, ‘defaultcf’] block-size 4KB

      rocksdb.defaultcf.disable-auto-compactions [‘rocksdb’, ‘defaultcf’] disable-auto-compactions False

    分析了一下,感觉是因为 write CF 比较小,当 block cache size 足够大时,bloom filter 的效果可能就不很明显了。

    如果仔细看一下结果,比较如下两个 sample,会发现一个现象:

    • 30 , 2019-08-23 03:03:42 , [3. 1. 1. 0. 0.] , [4.30542000e+04 1.18890000e+04 8.68628124e+10 5.10200000e+01]

    • 20 , 2019-08-22 16:09:26 , [3. 1. 0. 0. 0.] , [4.24397000e+04 1.20590000e+04 8.68403016e+10 5.07300000e+01]

    它们 knob 的唯一区别就是 30 号关闭了底层 bloom filter(optimize-filters-for-hitsTrue),20 号启用了底层 bloom filter(optimize-filters-for-hitsFalse)。结果 20 号的 throughput 比 30 还低了一点,和预期完全不一样。于是我们打开 Grafana 琢磨了一下,分别截取了这两个 sample 运行时段的图表:

    (两种场景 run 时候的 block-cache-size 都是 12.8GB)

    图中粉色竖线左边是 load 阶段,右边是 run 阶段。可以看出来这两种情况下 cache hit 其实相差不大,而且 20 号还稍微低一点点。这种情况是因为 bloom filter 本身也是占空间的,如果本来 block cache size 够用,但 bloom filter 占空间又比较大,就会影响 cache hit。这个一开始确实没有预料到。其实这是一个好事情,说明 ML 模型确实可以帮我们发现一些人工想不到的东西。

    接下来再试验一下 short range scan。这次要优化的 metric 改成 scan latency:

    workload=shortscan    knobs={'bloom-filter-bits-per-key', 'optimize-filters-for-hits', 'block-size', 'disable-auto-compactions'}  metric=scan_latency
    

    实验结果如下:

    由于篇幅有限我们先看前 45 轮的结果。这个推荐结果还没有完全收敛,但基本上满足 optimize-filters-for-hitsFalse,block-size32KB 或者 64KB,disable-auto-compactions==False,这三个也是对结果影响最明显的参数了。根据 Intel 的 SSD 白皮书,SSD 对 32KB 和 64KB 大小的随机读性能其实差不多。bloom filter 的位数对 scan 操作的影响也不大。这个实验结果也是符合预期了。

    与 OtterTune 的不同点

    我们的试验场景和 OtterTune 还是有一些区别的,主要集中在以下几点[3][4]:

    • AutoTiKV 直接和 DB 运行在同一台机器上,而不是像 OtterTune 一样设置一个集中式的训练服务器。但其实这样并不会占用很多资源,还避免了不同机器配置不一样造成数据不一致的问题。

    • 省去了 workload mapping(OtterTune 加了这一步来从 repository 中挑出和当前 workload 最像的训练样本,而我们目前默认 workload 类型只有一种)。

    • 要调的 knobs 比较少,省去了 identity important knobs(OtterTune 是通过 Lasso Regression 选出 10 个最重要的 knob 进行调优)。

    • 另外我们重构了 OtterTune 的架构,减少了对具体数据库系统的耦合度。更方便将整个模型和 pipeline 移植到其他系统上(只需修改 controller.py 中具体操作数据库系统的语句即可,其它都不用修改),也更适合比起 SQL 更加轻量的 KV 数据库。

    • 最后我们解决了 OtterTune 中只能调整 global knob,无法调节不同 session 中同名 knob 的问题。

    总结

    一个复杂的系统需要很多环节的取舍和平衡,才能使得总体运行效果达到最好。这需要对整个系统各个环节都有很深入的理解。而使用机器学习算法来做参数组合探索,确实会起到很多意想不到的效果。在我们的实验过程中,AutoTiKV 推荐的配置有些就和人工预期的情况不符,进而帮助我们发现了系统的一些问题:

    • 有些参数对结果的影响并没有很大。比如这个参数起作用的场景根本没有触发,或者说和它相关的硬件并没有出现性能瓶颈。

    • 有些参数直接动态调整是达不到效果的,或者需要跑足够长时间的 workload 才能看出效果。例如 block cache size 刚从小改大的一小段时间肯定是装不满的,必须要等 workload 足够把它填满之后,才能看出大缓存对总体 cache hit 的提升效果。

    • 有些参数的效果和预期相反,分析了发现该参数其实是有副作用的,在某些场景下就不大行了(比如上面的 bloom filter 那个例子)。

    • 有些 workload 并不是完全的读或者写,还会掺杂一些别的操作。而人工判断预期效果的时候很可能忽略这一点(比如上面的 writeheavy)。特别是在实际生产环境中,DBA 并不能提前知道会遇到什么样的 workload。这大概也就是自动调优的作用吧。

    后续我们还会对 AutoTiKV 继续进行改进,方向集中在以下几点:

    • 动态适应不断变化的 workload(比如一会读一会写),以及之前没有出现过的不同业务特征的 workload。

    • 有时 ML 模型有可能陷入局部最优(尝试的 knob 组合不全,限于若干个当前效果还不错的 knob 循环推荐了)。

    • 借鉴 AutoML 中的思路,尝试更多不同的 ML 模型来提高推荐效果,减少推荐所需时间。

    参考资料

    [1] https://mp.weixin.qq.com/s/y8VIieK0LO37SjRRyPhtrw

    [2] https://github.com/brianfrankcooper/YCSB/wiki/Core-Properties

    [3] https://www.cnblogs.com/pdev/p/10948322.html

    [4] https://www.cnblogs.com/pdev/p/10903628.html

    原文阅读https://pingcap.com/blog-cn/autotikv/

    展开全文
  • 作者:吴毅, 王远立TiKV 底层使用了 RocksDB 作为存储...如果有一个自动 tuning 的方案就可以大大减少调优的人力成本,同时也可能在调优的过程中,发现一些人工想不到的信息。我们从 AutoML 中得到启发,希望能用 A...

    作者:吴毅, 王远立

    TiKV 底层使用了 RocksDB 作为存储引擎,然而 RocksDB 配置选项很多,很多情况下只能通过反复测试或者依靠经验来调优,甚至连 RocksDB 的开发者都自嘲,他们没办法弄清楚每个参数调整对性能的影响。如果有一个自动 tuning 的方案就可以大大减少调优的人力成本,同时也可能在调优的过程中,发现一些人工想不到的信息。我们从 AutoML 中得到启发,希望能用 Automated Hyper-parameter Tuning 中的一些方法来对数据库参数进行自动调优。

    常用的 Automated Hyper-parameter Tuning 方式大体上有以下三种:

    1. 随机搜索,或者说叫启发式搜索。包括 GridSearch 和 RandomSearch。这种方法的改进空间主要体现在使用不同的采样方法生成配置,但本质上仍然是随机试验不同的配置,没有根据跑出来的结果来反馈指导采样过程,效率比较低。
    2. Multi-armed Bandit。这种方法综合考虑了“探索”和“利用”两个问题,既可以配置更多资源(也就是采样机会)给搜索空间中效果更优的一部分,也会考虑尝试尽量多的可能性。Bandit 结合贝叶斯优化,就构成了传统的 AutoML 的核心。
    3. 深度强化学习。强化学习在 AutoML 中最著名的应用就是 NAS,用于自动生成神经网络结构。另外它在 深度学习参数调优 中也有应用。它的优点是从“从数据中学习”转变为“从动作中学习”(比如 knob 中的 cache size 从小调到大),既可以从性能好的样本中学习,也可以从性能坏的样本中学习。但强化学习的坑也比较多,体现在训练可能比较困难,有时结果比较难复现。

    目前学术界针对 auto-tune 数据库的研究也有很多,采用的方法大多集中在后面两种。其中一个比较有名的研究是 OtterTune 。我们受 OtterTune 的启发,开发了 AutoTiKV,一个用于对 TiKV 数据库进行自动调优的工具。项目启动三个月以来,AutoTiKV 在 TiKV 内部测试和调参的环节起到了较好的效果,有了一个很好的开始。后续我们还会针对生产环境上的一些特点,对它进行继续探索和完善。

    项目地址:https://github.com/tikv/auto-tikv

    设计目标

    整个调优过程大致如下图:

    0f711e5f30bc60e3a9743c4faccb49d6.png

    整个过程会循环跑 200 个 round(可以用户自定义),或者也可以定义成到结果收敛为止。

    AutoTiKV 支持在修改参数之后重启 TiKV(如果不需要也可以选择不重启)。需要调节的参数和需要查看的 metric 可以在 controller.py 里声明。

    一开始的 10 轮(具体大小可以调节)是用随机生成的 knob 去 benchmark,以便收集初始数据集。之后的都是用 ML 模型推荐的参数去 benchmark。

    ML 模型

    AutoTiKV 使用了和 OtterTune 一样的高斯过程回归(Gaussian Process Regression,以下简称 GP)来推荐新的 knob[1],它是基于高斯分布的一种非参数模型。高斯过程回归的好处是:

    1. 和神经网络之类的方法相比,GP 属于无参数模型,算法计算量相对较低,而且在训练样本很少的情况下表现比 NN 更好。
    2. 它能估计样本的分布情况,即 X 的均值 m(X) 和标准差 s(X)。若 X 周围的数据不多,则它被估计出的标准差 s(X) 会偏大(表示这个样本 X 和其他数据点的差异大)。直观的理解是若数据不多,则不确定性会大,体现在标准差偏大。反之,数据足够时,不确定性减少,标准差会偏小。这个特性后面会用到。

    但 GP 本身其实只能估计样本的分布,为了得到最终的预测值,我们需要把它应用到贝叶斯优化(Bayesian Optimization)中。贝叶斯优化算法大致可分为两步:

    1. 通过 GP 估计出函数的分布情况。
    2. 通过采集函数(Acquisition Function)指导下一步的采样(也就是给出推荐值)。

    采集函数(Acquisition Function)的作用是:在寻找新的推荐值的时候,平衡探索(exploration)和利用(exploitation)两个性质:

    • exploration:在目前数据量较少的未知区域探索新的点。
    • exploitation:对于数据量足够多的已知区域,利用这些数据训练模型进行估计,找出最优值。

    在推荐的过程中,需要平衡上述两种指标。exploitation 过多会导致结果陷入局部最优值(重复推荐目前已知的最好的点,但可能还有更好的点没被发现),而 exploration 过多又会导致搜索效率太低(一直在探索新区域,而没有对当前比较好的区域进行深入尝试)。而平衡二者的核心思想是:当数据足够多时,利用现有的数据推荐;当缺少数据时,我们在点最少的区域进行探索,探索最未知的区域能给我们最大的信息量。

    贝叶斯优化的第二步就可以帮我们实现这一思想。前面提到 GP 可以帮我们估计 X 的均值 m(X) 和标准差 s(X),其中均值 m(x) 可以作为 exploitation 的表征值,而标准差 s(x) 可以作为 exploration 的表征值。这样就可以用贝叶斯优化方法来求解了。

    使用置信区间上界(Upper Confidence Bound)作为采集函数。假设我们需要找 X 使 Y 值尽可能大,则 U(X) = m(X) + k*s(X),其中 k > 0 是可调的系数。我们只要找 X 使 U(X) 尽可能大即可。

    • U(X) 大,则可能 m(X) 大,也可能 s(X) 大。
    • s(X) 大,则说明 X 周围数据不多,需要探索未知区域新的点。
    • m(X) 大,说明估计的 Y 值均值大, 则需要利用已知数据找到效果好的点。
    • 其中系数 k 影响着探索和利用的比例,k 越大,越鼓励探索新的区域。

    在具体实现中,一开始随机生成若干个 candidate knobs,然后用上述模型计算出它们的 U(X),找出 U(X) 最大的那一个作为本次推荐的结果。

    数据库参数

    workload

    测试中我们使用了 YCSB 来模拟 write heavy、long range scan、short range scan 和 point-lookup 四种典型 workload。数据库大小都是 80GB。[2]

    knobs

    我们试验了如下参数:

    bf9efbd851b3280f9e130f2f0c00194d.png

    这些参数的含义如下:

    • block-size:RocksDB 会将数据存放在 data block 里面,block-size 设置这些 block 的大小,当需要访问某一个 key 的时候,RocksDB 需要读取这个 key 所在的整个 block。对于点查,更大的 block 会增加读放大,影响性能,但是对于范围查询,更大的 block 能够更有效的利用磁盘带宽。
    • disable-auto-compactions:定义是否关闭 compaction。compaction 会占用磁盘带宽,影响写入速度。但如果 LSM 得不到 compact, level0 文件会累积,影响读性能。其实本身 compaction 也是一个有趣的 auto-tuning 的方向。
    • write-buffer-size:单个 memtable 的大小限制(最大值)。理论上说更大的 memtable 会增加二分查找插入位置的消耗,但是之前的初步试验发现这个选项对 writeheavy 影响并不明显。
    • max-bytes-for-level-base:LSM tree 里面 level1 的总大小。在数据量固定的情况下,这个值更大意味着其实 LSM 的层数更小,对读有利。
    • target-file-size-base:假设 target-file-size-multiplier=1 的情况下,这个选项设置的是每个 SST 文件的大小。这个值偏小的话意味着 SST 文件更多,会影响读性能。
    • bloom-filter-bits-per-key:设置 Bloom Filter 的位数。对于读操作这一项越大越好。
    • optimize-filters-for-hits:True 表示关闭 LSM 最底层的 bloom filter。这个选项主要是因为最底层的 bloom filter 总大小比较大,比较占用 block cache 空间。如果已知查询的 key 一定在数据库中存,最底层 bloom filter 其实是没有作用的。

    metrics

    我们选择了如下几个 metrics 作为优化指标。

    • throughput:根据具体 workload 不同又分为 write throughput、get throughput、scan throughput
    • latency:根据具体 workload 不同又分为 write latency、get latency、scan latency
    • store_size
    • compaction_cpu

    其中 throughput 和 latency 通过 go-ycsb 的输出结果获得,store_size 和 compaction_cpu 通过 tikv-ctl 获得。

    实验测试结果

    测试平台

    AMD Ryzen5-2600 (6C12T),32GB RAM,512GB NVME SSD,Ubuntu 18.04,tidb-ansible 用的 master 版本。

    所有的实验都是前 10 轮用随机生成的配置,后面使用模型推荐的配置:

    workload=writeheavy  knobs={disable-auto-compactions, block-size}  metric=write_latency

    实验效果如下:

    6474545fede8cc0a9c159f10ae53bac2.png

    这个实验中推荐结果是启用 compaction、同时 block size 设为 4KB。

    虽然一般来说写入时需要关闭 compaction 以提升性能,但分析后发现由于 TiKV 使用了 Percolator 进行分布式事务,写流程也涉及读操作(写冲突检测),所以关闭 compaction 也导致写入性能下降。同理更小的 block size 提高点查性能,对 TiKV 的写流程性能也有提升。

    接下来用 point lookup 这一纯读取的 workload 进行了试验:

    workload=pntlookup80  knobs={'bloom-filter-bits-per-key', 'optimize-filters-for-hits', 'block-size', 'disable-auto-compactions'}  metric=get_latency

    实验效果如下:

    7d52deae118cd035f3f29ebae230d433.png

    推荐结果为:bloom-filter-bits-per-key==20,block-size==4K,不 disable auto compaction。而 optimize-filters-for-hits 是否启用影响不大(所以会出现这一项的推荐结果一直在摇摆的情况)。

    推荐的结果都挺符合预期的。关于 optimize-filter 这一项,应该是试验里面 block cache 足够大,所以 bloom filter 大小对 cache 性能影响不大;而且我们是设置 default CF 相应的选项(关于 TiKV 中对 RocksDB CF 的使用,可以参考 《TiKV 是如何存取数据的》),而对于 TiKV 来说查询 default CF 之前我们已经确定相应的 key 肯定存在,所以是否有 filter 并没有影响。之后的试验中我们会设置 writeCF 中的 optimize-filters-for-hits(defaultCF 的这一项默认就是 0 了);然后分别设置 defaultCF 和 writeCF 中的 bloom-filter-bits-per-key,把它们作为两个 knob。

    为了能尽量测出来 bloom filter 的效果,除了上述改动之外,我们把 workload 也改了一下:把 run phase 的 recordcount 设成 load phase 的两倍大,这样强制有一半的查找对应的 key 不存在,这样应该会测出来 write CF 的 optimize-filters-for-hits 必须关闭。改完之后的 workload 如下:

    workload=pntlookup80  knobs={rocksdb.writecf.bloom-filter-bits-per-key,  rocksdb.defaultcf.bloom-filter-bits-per-key, rocksdb.writecf.optimize-filters-for-hits,  rocksdb.defaultcf.block-size, rocksdb.defaultcf.disable-auto-compactions}  metric=get_throughput

    这次的实验效果如下(发现一个很出乎意料的现象):

    987274c9e3e687d19f7d32e9155ae556.png

    测出来发现推荐配置基本集中在以下两种:

    • {3,1,1,0,0}

    rocksdb.writecf.bloom-filter-bits-per-key [‘rocksdb’, ‘writecf’] bloom-filter-bits-per-key 20

    rocksdb.defaultcf.bloom-filter-bits-per-key [‘rocksdb’, ‘defaultcf’] bloom-filter-bits-per-key 10

    rocksdb.writecf.optimize-filters-for-hits [‘rocksdb’, ‘writecf’] optimize-filters-for-hits True

    rocksdb.defaultcf.block-size [‘rocksdb’, ‘defaultcf’] block-size 4KB

    rocksdb.defaultcf.disable-auto-compactions [‘rocksdb’, ‘defaultcf’] disable-auto-compactions False

    • {2,2,0,0,0}

    rocksdb.writecf.bloom-filter-bits-per-key [‘rocksdb’, ‘writecf’] bloom-filter-bits-per-key 15

    rocksdb.defaultcf.bloom-filter-bits-per-key [‘rocksdb’, ‘defaultcf’] bloom-filter-bits-per-key 15

    rocksdb.writecf.optimize-filters-for-hits [‘rocksdb’, ‘writecf’] optimize-filters-for-hits False

    rocksdb.defaultcf.block-size [‘rocksdb’, ‘defaultcf’] block-size 4KB

    rocksdb.defaultcf.disable-auto-compactions [‘rocksdb’, ‘defaultcf’] disable-auto-compactions False

    分析了一下,感觉是因为 write CF 比较小,当 block cache size 足够大时,bloom filter 的效果可能就不很明显了。

    如果仔细看一下结果,比较如下两个 sample,会发现一个现象:

    • 30 , 2019-08-23 03:03:42 , [3. 1. 1. 0. 0.] , [4.30542000e+04 1.18890000e+04 8.68628124e+10 5.10200000e+01]
    • 20 , 2019-08-22 16:09:26 , [3. 1. 0. 0. 0.] , [4.24397000e+04 1.20590000e+04 8.68403016e+10 5.07300000e+01]

    它们 knob 的唯一区别就是 30 号关闭了底层 bloom filter(optimize-filters-for-hits==True),20 号启用了底层 bloom filter(optimize-filters-for-hits==False)。结果 20 号的 throughput 比 30 还低了一点,和预期完全不一样。于是我们打开 Grafana 琢磨了一下,分别截取了这两个 sample 运行时段的图表:

    (两种场景 run 时候的 block-cache-size 都是 12.8GB)

    dcacd563d58523140154494cd9ab6be6.png

    图中粉色竖线左边是 load 阶段,右边是 run 阶段。可以看出来这两种情况下 cache hit 其实相差不大,而且 20 号还稍微低一点点。这种情况是因为 bloom filter 本身也是占空间的,如果本来 block cache size 够用,但 bloom filter 占空间又比较大,就会影响 cache hit。这个一开始确实没有预料到。其实这是一个好事情,说明 ML 模型确实可以帮我们发现一些人工想不到的东西。

    接下来再试验一下 short range scan。这次要优化的 metric 改成 scan latency:

    workload=shortscan    knobs={'bloom-filter-bits-per-key', 'optimize-filters-for-hits', 'block-size', 'disable-auto-compactions'}  metric=scan_latency

    实验结果如下:

    24d3876b90af95417792b3abb01867f6.png

    由于篇幅有限我们先看前 45 轮的结果。这个推荐结果还没有完全收敛,但基本上满足 optimize-filters-for-hits==False,block-size==32KB 或者 64KB,disable-auto-compactions==False,这三个也是对结果影响最明显的参数了。根据 Intel 的 SSD 白皮书,SSD 对 32KB 和 64KB 大小的随机读性能其实差不多。bloom filter 的位数对 scan 操作的影响也不大。这个实验结果也是符合预期了。

    与 OtterTune 的不同点

    我们的试验场景和 OtterTune 还是有一些区别的,主要集中在以下几点[3][4]:

    • AutoTiKV 直接和 DB 运行在同一台机器上,而不是像 OtterTune 一样设置一个集中式的训练服务器。但其实这样并不会占用很多资源,还避免了不同机器配置不一样造成数据不一致的问题。
    • 省去了 workload mapping(OtterTune 加了这一步来从 repository 中挑出和当前 workload 最像的训练样本,而我们目前默认 workload 类型只有一种)。
    • 要调的 knobs 比较少,省去了 identity important knobs(OtterTune 是通过 Lasso Regression 选出 10 个最重要的 knob 进行调优)。
    • 另外我们重构了 OtterTune 的架构,减少了对具体数据库系统的耦合度。更方便将整个模型和 pipeline 移植到其他系统上(只需修改 controller.py 中具体操作数据库系统的语句即可,其它都不用修改),也更适合比起 SQL 更加轻量的 KV 数据库。
    • 最后我们解决了 OtterTune 中只能调整 global knob,无法调节不同 session 中同名 knob 的问题。

    总结

    一个复杂的系统需要很多环节的取舍和平衡,才能使得总体运行效果达到最好。这需要对整个系统各个环节都有很深入的理解。而使用机器学习算法来做参数组合探索,确实会起到很多意想不到的效果。在我们的实验过程中,AutoTiKV 推荐的配置有些就和人工预期的情况不符,进而帮助我们发现了系统的一些问题:

    • 有些参数对结果的影响并没有很大。比如这个参数起作用的场景根本没有触发,或者说和它相关的硬件并没有出现性能瓶颈。
    • 有些参数直接动态调整是达不到效果的,或者需要跑足够长时间的 workload 才能看出效果。例如 block cache size 刚从小改大的一小段时间肯定是装不满的,必须要等 workload 足够把它填满之后,才能看出大缓存对总体 cache hit 的提升效果。
    • 有些参数的效果和预期相反,分析了发现该参数其实是有副作用的,在某些场景下就不大行了(比如上面的 bloom filter 那个例子)。
    • 有些 workload 并不是完全的读或者写,还会掺杂一些别的操作。而人工判断预期效果的时候很可能忽略这一点(比如上面的 writeheavy)。特别是在实际生产环境中,DBA 并不能提前知道会遇到什么样的 workload。这大概也就是自动调优的作用吧。

    后续我们还会对 AutoTiKV 继续进行改进,方向集中在以下几点:

    • 动态适应不断变化的 workload(比如一会读一会写),以及之前没有出现过的不同业务特征的 workload。
    • 有时 ML 模型有可能陷入局部最优(尝试的 knob 组合不全,限于若干个当前效果还不错的 knob 循环推荐了)。
    • 借鉴 AutoML 中的思路,尝试更多不同的 ML 模型来提高推荐效果,减少推荐所需时间。
    参考资料
    [1] https://mp.weixin.qq.com/s/y8VIieK0LO37SjRRyPhtrw
    [2] https://github.com/brianfrankcooper/YCSB/wiki/Core-Properties
    [3] https://www.cnblogs.com/pdev/p/10948322.html
    [4] https://www.cnblogs.com/pdev/p/10903628.html

    原文阅读:

    AutoTiKV:基于机器学习的数据库调优 | PingCAPpingcap.com
    f3cb96046ba3fc66fcc80c0a507f2cd4.png
    展开全文
  • {管理信息化 ORACLE}Oracle10g 数据 库性能调优办法研究 内容摘要数据库系统性能最终了决定数据库的可用性和生命力大多数数据 库系统在运行一段时间后都会存在一定性能问题主要涉及数据库硬件数据 库服务器...
  • 数据库性能调优

    2019-11-06 11:25:20
    1.1、最有可能影响性能是磁盘和网络吞吐量,解决办法扩大虚拟内存,并保证有足够可以扩充空间把数据库服务器上不必要服务关闭掉 1.2、把数据库服务器和主域服务器分开;把SQL数据库服务器吞吐量调为最大;在...

    数据库性能调优方案

    1) 硬件调整性能

    1.1、最有可能影响性能的是磁盘网络吞吐量,解决办法扩大虚拟内存,并保证有足够可以扩充的空间把数据库服务器上的不必要服务关闭掉

    1.2、把数据库服务器和主域服务器分开;把SQL数据库服务器的吞吐量调为最大;在具有一个以上处理器的机器上运行SQL。

    2)调整数据库

    2.1、要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引 

    2.2、在经常需要进行检索的字段上创建索引

    2.3、一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有 必要

    3)使用存储过程

    应用程序的实现过程中,能够采用存储过程实现的对数据库的操作尽量通过存储过程来实现,因为存储过程是存放在数据库服务器上的一次性被设计、编码、测试,并被再次使用,需要执行该任务的应用可以简单地执行存储过程,并且只返回结果集或者数值,这样不仅可以使程序模块化,同时提高响应速度,减少网络流量,并且通过输入参数接受输入,使得在应用中完成逻辑的一致性实现。

    4)使用预编译查询

    程序中通常是根据用户的输入来动态执行SQL,这时应该尽量使用参数化SQL,这样不仅可以避免SQL注入漏洞 
    攻击,最重要数据库会对这些参数化SQL进行预编译,这样第一次执行的时候DBMS会为这个SQL语句进行查询优化 
    并且执行预编译,这样以后再执行这个SQL的时候就直接使用预编译的结果,这样可以大大提高执行的速度。

    5)调整Where字句中的连接顺序

    DBMS一般采用自下而上的顺序解析where字句,根据这个原理表连接最好写在其他where条件之前,那些可以 
    过滤掉最大数量记录。

    6)尽量将多条SQL语句压缩到一句SQL中

    每次执行SQL的时候都要建立网络连接、进行权限校验、进行SQL语句的查询优化、发送执行结果,这个过程 
    是非常耗时的,因此应该尽量避免过多的执行SQL语句,能够压缩到一句SQL执行的语句就不要用多条来执行。

    7)用where字句替换HAVING字句

    避免使用HAVING字句,因为HAVING只会在检索出所有记录之后才对结果集进行过滤,而where则是在聚合前 
    刷选记录,如果能通过where字句限制记录的数目,那就能减少这方面的开销。HAVING中的条件一般用于聚合函数 
    的过滤,除此之外,应该将条件写在where字句中。

    8)使用表的别名

    当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于每个列名上。这样就可以减少解析的时间并减 
    少哪些友列名歧义引起的语法错误。

    9)用union all替换union

    当SQL语句需要union两个查询结果集合时,即使检索结果中不会有重复的记录,如果使用union这两个结果集 
    同样会尝试进行合并,然后在输出最终结果前进行排序,因此如果可以判断检索结果中不会有重复的记录时候,应 
    该用union all,这样效率就会因此得到提高。

    10)考虑使用“临时表”暂存中间结果

    简化SQL语句的重要方法就是采用临时表暂存中间结果,但是,临时表的好处远远不止这些,将临时结果暂存在临时表,后面的查询就在tempdb中了,这可以避免程序中多次扫描主表,也大大减少了程序执行中“共享锁”阻塞“更新锁”,减少了阻塞,提高了并发性能。 但是也得避免频繁创建和删除临时表,以减少系统表资源的消耗。

    11)只在必要的情况下才使用事务begin translation

    SQL Server中一句SQL语句默认就是一个事务,在该语句执行完成后也是默认commit的。其实,这就是begin tran的一个最小化的形式,好比在每句语句开头隐含了一个begin tran,结束时隐含了一个commit。 
    有些情况下,我们需要显式声明begin tran,比如做“插、删、改”操作需要同时修改几个表,要求要么几个表都修改成功,要么都不成功。begin tran 可以起到这样的作用,它可以把若干SQL语句套在一起执行,最后再一起commit。 好处是保证了数据的一致性,但任何事情都不是完美无缺的。Begin tran付出的代价是在提交之前,所有SQL语句锁住的资源都不能释放,直到commit掉。 可见,如果Begin tran套住的SQL语句太多,那数据库的性能就糟糕了。在该大事务提交之前,必然会阻塞别的语句,造成block很多。 Begin tran使用的原则是,在保证数据一致性的前提下,begin tran 套住的SQL语句越少越好!有些情况下可以采用触发器同步数据,不一定要用begin tran。

    12)尽量避免使用游标

    尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。

    13)用varchar/nvarchar 代替 char/nchar

    尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。 
    不要以为 NULL 不需要空间,比如:char(100) 型,在字段建立时,空间就固定了, 不管是否插入值(NULL也包含在内),都是占用 100个字符的空间的,如果是varchar这样的变长字段, null 不占用空间。

    14)查询select语句优化

    1、任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段 
    2、应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描, 

    15)更新Update语句优化

    1、如果只更改1、2个字段,不要Update全部字段,否则频繁调用会引起明显的性能消耗,同时带来大量日志

    16)删除Delete语句优化语句

    1、最高效的删除重复记录方法 ( 因为使用了ROWID)例子: 

    DELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID) FROM EMP X WHERE X.EMP_NO = E.EMP_NO);

    17)插入Insert语句优化

    1、在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。

    展开全文
  • 这篇文章主要是针对e-business OLTP10个性能方面Tips。10. Monitor Switches打开Monitor Switch,才能获得性能方面信息,命令如下db2 "update monitor switches using lock ON sort ON bufferpool ON uow ON ...
  • 涉及了数据库应用系统调优的五大领域:压力测试、 应用端调优、服务器端调优、系统平台层的优化、应用架构的优化,详细介绍了作者在项目开发过程中曾经遇到的各种问题及其解决办法。本文通过对“企业级 S...
  • 测试发现数据库性能问题后SQL调优 对单表超过300w+数据Web应用程序进行测试后发现了一些功能、性能问题,采取了以下办法来进行调整:  将绝大部分SQL查询改为存储过程,这样操作毫无疑问可以...
  • MySQL性能调优办法

    2019-09-26 17:48:01
    1.数据库的设计 尽量把数据库设计更小占磁盘空间. 1).尽可能使用更小整数类型.(mediumint就比int更合适). 2).尽可能定义字段为not null,除非这个字段需要null. 3).如果没有用到变长字段话比如varchar,那就...
  • 在曩昔的十年中,Oracle现已...最有用的办法之一是经过Oracle调优。它有许多的调整参数和技能来改进你的Oracle数据库的功能。 Oracle调优是一个杂乱的主题。关于调优能够写整整一本书,不过,为了改进Oracle数据...
  • 对单表超过300w+数据Web应用程序进行测试后发现了一些功能、性能问题,采取了以下办法来进行调整
  • 一、最好的优化-----不查询! 这不是开玩笑. 如果一台服务器出现长时间负载过高 /周期性负载过大,或偶尔卡住,如何来处理?... 具体到单条语句, 这条语句是在等待上花的时间,还是查询上花的时间. ... 唯一的办法--
  • 做个性能调优,也看过别人的性恩调优,我认为有三种吹毛求疵的性能...虚拟机调优在我看来,是调优的最后一步,也就是说,其他办法你都用了但你老板还要你做的更好,那就只好采用虚拟机调优。但虚拟机调优真的有用么...
  • Kettle调优

    2018-09-09 18:30:36
    Kettle调优 1、让kettle执行速度飞起来 ... Kettle之效率提升。  Kettle作为一款ETL工具,肯定无法避免遇到效率问题,当很大数据源...对需要进行查询的数据库端字段,创建索引,可以在很大程度上提升查询效...
  • Django性能调优

    2019-10-08 09:47:59
    1.针对数据库的调优 程序对数据库的多次访问,会影响速度。 一般流程是建立连接,获取或者修改数据,关闭连接。如果多次请求,导致多次建立连接会影响到速度。  解决办法有:1.延长连接时间并执行多次操作 2....
  •  最近在项目中需要往数据库中添加测试数据,大概只有几百W条的样子,但是可能我给它做了其他的操作,反正是表空间异常不足,甚至是报出了无法通过128/8进行扩展的错误,后来找到的解决的办法,也就是扩一下表...

空空如也

空空如也

1 2 3 4 5 6
收藏数 106
精华内容 42
关键字:

数据库调优的办法