• 快速排序算法


    在分析redis集群中大Key的时候,通常都采用分析rdb文件的方式;但是这种方式需要在每一台redis服务器上部署分析程序及分析脚本,而像salt之类的工具运维没有开放给我们使用,一台一台部署不好管理。正好我们的总redis规模不大,大概在200个集群左右,考虑到cluster集群,需要分析的redis实例数在300左右,所以就想着能不能通过scan的方式来进行。

    通过scan命令扫描从库,将集群中key深度大于指定值的key扫描出来,将这些 key 放在一个slice中,取 top N,这就需要对 slice中的 key按照深度进行排序。300个实例说多不多,说少不少,排序算法的性能还是很重要的。快速排序针对小数据量排序性能很好,正好mysql在使用sort buffer进行排序时采用的是快速排序,这里就用go实现来复习一下快速排序算法。

    func sortBigKeySlice(bigKeySlice []*bigKeyInstance) {
       if len(bigKeySlice) < 2 {
          return
       }
       sortBigKey(bigKeySlice, 0, len(bigKeySlice))
    }
    
    //使用递归实现
    func sortBigKey(bigKeySlice []*bigKeyInstance, low, high int) {
       if low >= high {
          return
       }
       p := partition(bigKeySlice, low, high)
       sortBigKey(bigKeySlice, low, p)
       sortBigKey(bigKeySlice, p + 1, high)
    }
    
    //普通快速排序,对于普通快速排序,将第一个元素作为基准,小于该元素的放在左边,大于等于该元素的放在右边
    func partition(bigKeySlice []*bigKeyInstance, low, high int) int{
       //直接将第一个元素作为分隔值
       pivotIns := bigKeySlice[low]
       //当前第一个元素点位作为标记点
       pivotPos := low
    
       //去除第一个分割值,遍历元素,如果元素比分割值小,将标记点右移一位,交换元素的值,大于等于则继续比较下一个元素
       for i := low + 1; i < high; i++ {
          if bigKeySlice[i].size < pivotIns.size {
             pivotPos += 1
             bigKeySlice[pivotPos], bigKeySlice[i] = bigKeySlice[i], bigKeySlice[pivotPos]
          } else {
             continue
          }
       }
       //不要忘记最后的互换,将分隔值与标记点元素互换
       bigKeySlice[low], bigKeySlice[pivotPos] = bigKeySlice[pivotPos], bigKeySlice[low]
       return pivotPos
    }
    

      

    普通快速排序默认左边的第一个元素作为基准数,对于渐进有序的数组来说,这就导致小于基准的数会相当少,而大于等于基准的数相当多,造成分区不平衡的问题,普通排序就会退化,严重的将退化成O(n^2)。所以对其改进:不再默认选择第一个数,而是随机选一个数作为基准,这样的快排称为随机普通快排。

    //随机普通快速排序,不使用第一个元素作为基准,而是使用一个随机元素作为基准
    func partition(bigKeySlice []*bigKeyInstance, low, high int) int {
    	//取slice中的一个随机元素作为分割点,而不是第一个元素开始分割
    	rand_low := low + rand.Intn(high - low)
    	bigKeySlice[low], bigKeySlice[rand_low] = bigKeySlice[rand_low], bigKeySlice[low]
    	pivotPos := low
    	for i := low + 1; i < high; i++ {
    		if bigKeySlice[i].size < bigKeySlice[low].size {
    			pivotPos += 1
    			bigKeySlice[pivotPos], bigKeySlice[i] = bigKeySlice[i], bigKeySlice[pivotPos]
    		} else {
    			continue
    		}
    	}
    	bigKeySlice[low], bigKeySlice[pivotPos] = bigKeySlice[pivotPos], bigKeySlice[low]
    	return pivotPos
    }
    

      

    对于含有大量重复元素的数组,则对于与基准数相同的数,要么分到了左边,要么分到了右边,同样会造成分治不平衡的问题,造成性能退化。这时,采用双路排序或三路排序进行改进。

    双路排序 & 三路排序待续....

  • 相关阅读:
    盘点 Oracle 11g 中新特性带来的10大性能影响
    史上最全Oracle数据泵常用命令
    Oracle查看 open_cursors 和 session_cached_cursors
    SLES 12: Database Startup Error with ORA-27300 ORA-27301 ORA-27303 While Starting using Srvctl (Doc ID 2340986.1)
    FAQ: Oracle Flex ASM 12c / 12.1 (Doc ID 1573137.1)
    Test Case:: 12C ASM New feature (Doc ID 1571975.1)
    Test Case:: 12C ASMCMD New feature (Doc ID 1589249.1)
    如何在Oracle 12C中Drop/Truncate多个分区 (Doc ID 1482264.1)
    如何在Oracle 12C中添加多个分区 (Doc ID 1482456.1)
    12c分区增强功能,新功能(文档ID 1568010.1)
  • 原文地址:https://www.cnblogs.com/juanmaofeifei/p/13428048.html
Copyright © 2020-2023  润新知