您正在查看: 软件开发 分类下的文章

[性能优化] MySQL ORDER BY RAND()的替代方案

这是开发签到助手时遇到的问题……

需求:从数据库取没有签到的TID

原来的代码:

SELECT tid FROM sign_log WHERE status IN (0, 1) AND date='{$date}' ORDER BY RAND() LIMIT 0,1

当 sign_log 这个表非常大的时候,会出现 filesort 罢工的现象

EXPLAIN 的提示:Using where; Using temporary; Using filesort

这是由于 MySQL 在执行过程中需要遍历数据库,然后给每行分配一个权重值(因为用的是RAND函数),之后再用 filesort 的方式排序临时表,最后输出。

只是取一个tid而已……有必要遍历整个表么?有没有替代的方案呢?

答案是肯定的。这个算法分为3步,将上面一个查询拆解为2个:

1.从数据库取出最大数据量:

SELECT COUNT(*) FROM `sign_log` WHERE status IN (0, 1) AND date='{$date}'

2.用 PHP 的 rand 函数计算出 offset 值

$offset = rand(1, $count) - 1;

3.直接从数据库取出这一行的tid:

SELECT tid FROM `sign_log` LIMIT {$offset},1

(再次运行时可以略过第一步)

测试结果(共13506行数据):

ORDER BY RAND():
Using where; Using temporary; Using filesort
运行时间:0.0050160884857178秒

优化后:
查询1:Using where
查询2:Using index(注:tid字段有索引)
总运行时间:0.0021970272064209秒

改进后不仅提升了运行速度,还解决了 filesort 数据量上限的问题

[源码] Java简易计算器

这学期程序设计学的是Java,期末要求制作一个计算器:

QQ截图20130621125013.png

花了一个晚上搞定,CalcWindow类负责界面绘制,Main类是主程序,关键代码如下:

package com.kookxiang.calc;
import javax.swing.JOptionPane;
public class Main {
    CalcWindow UI;
    double cur_num = 0;
    double prev_num = 0;
    boolean autoclean = false;
    boolean dotted = false;
    boolean last_equal = true;
    int mode = Mode.ADD;
    public void clear(){
        cur_num = prev_num = 0;
        autoclean = dotted = false;
        last_equal = true;
        mode = Mode.ADD;
        UI.numberBox.setText("0");
    }
    public void cal(){
        boolean _last_equal = last_equal;
        last_equal = true;
        String txt=UI.numberBox.getText();
        if(!_last_equal) eval();
        switch(mode){
            case Mode.ADD:          prev_num = prev_num + cur_num;  break;
            case Mode.MINUS:        prev_num = prev_num - cur_num;  break;
            case Mode.MUILTIPLY:    prev_num = prev_num * cur_num;  break;
            case Mode.DIVISION:     prev_num = prev_num / cur_num;  break;
        }
        txt = prev_num+"";
        UI.numberBox.setText(txt);
        http:// 消掉结尾的 *.0
        if(txt.endsWith(".0")) UI.numberBox.setText(txt.substring(0, txt.length()-2));
        autoclean = true;
        if(Double.isNaN(prev_num) || Double.isInfinite(prev_num)){
            clear();
            JOptionPane.showMessageDialog(null, "发生未知错误");
        }
    }
    public void eval(){
        if(!last_equal) cal();
        prev_num = cur_num;
        dotted = false;
        autoclean = true;
        cur_num = Double.parseDouble(UI.numberBox.getText());
    }
    public void onCreate(String[] flags){
        UI = new CalcWindow(this);
        clear();
    }
    public static void main(String[] args) {
        new Main().onCreate(args);
    }
    public void handleAction(String command) throws Exception {
        String txt=UI.numberBox.getText();
        if(txt.equals("0")) txt = "";
        switch(command){
            case "exit":    System.exit(0);     break;
            case "clear":   clear();    break;
            case "backspace":
                if(txt.isEmpty()) return;
                if(autoclean){
                    UI.numberBox.setText("");
                    autoclean = false;
                    return;
                }
                UI.numberBox.setText(txt.substring(0, txt.length()-1));
                break;
            case "dot":
                if(dotted) return;
                dotted = true;
                command = ".";
            case "1":   case "2":   case "3":   case "4":   case "5":   case "6":   case "7":   case "8":   case "9":   case "0":   case ".":
                UI.numberBox.setText(autoclean ? command : txt + command);
                autoclean = false;
                last_equal = false;
                break;
            case "dn":
                if(txt.isEmpty()) return;
                if(txt.substring(0, 1).equals("-")){
                    UI.numberBox.setText(txt.substring(1));
                }else{
                    UI.numberBox.setText("-"+txt);
                }
                break;
            case "add":         if(txt.isEmpty()) return; eval();   mode = Mode.ADD;        break;
            case "minus":       if(txt.isEmpty()) return; eval();   mode = Mode.MINUS;      break;
            case "multiply":    if(txt.isEmpty()) return; eval();   mode = Mode.MUILTIPLY;  break;
            case "division":    if(txt.isEmpty()) return; eval();   mode = Mode.DIVISION;   break;
            case "cal":         cal();  break;
            default:    throw new Exception("Unknown command");
        }
    }
}


完整源代码下载:Calculator.rar

【汉化】Yet Another Aria2 Web Frontend

先介绍下Aria2(摘自http://wiki.ubuntu.org.cn):

Aria2是一个命令行下运行、多协议、多来源下载工具(HTTP/HTTPS、FTP、BitTorrent、Metalink),内建 XML-RPC 用户界面。

既然是命令行下工作的,那么管理必然是一个难题,好在它提供了JSON-RPC的功能,也就有了Web管理界面

YAAW算是所有管理界面中最简洁、清爽的了,源地址在这里:https://github.com/binux/yaaw

QQ截图20130511020627.png

看了网上很多汉化版,没有自己满意的。

要么汉化不完整,要么相关术语翻译不准确,让人听起来不知所云

于是自己动手汉化了下,反正都是HTML和JS,汉化难度也不大:

QQ截图20130511020614.png

汉化后的项目:https://github.com/kookxiang/yaaw

另外:本人有严重洁癖,所以将网址中的###去掉了……

[续] 一键检测QQ群重复成员

上一篇《清理两个QQ群中的重复成员》发布后,Coxxs 童鞋给出了一个Anti-CSRF参数的算法,于是趁着周末又更新了一下。

这回全部用js实现了,使用方法如下:

  1. 拖放“搜索QQ群重复成员”到你的收藏夹

  2. 登陆QQ群空间 qun.qq.com

  3. 点击书签,按提示选择即可

失落的圣诞节

嗯,今天是2012年的圣诞节,听到2012和圣诞节就想到了这作品……

  《罪恶王冠:失落的圣诞节》是动画《罪恶王冠》的外传。所以要是你没看过Guilty Crown这部神作的话还是先看了再玩会比较好。下载地址:

磁力链接下载 (请保证安装了迅雷或其他支持磁力链接的下载工具!)

  游戏中的时间追溯到了动画版的10年前,突然其来的致命病毒Apocalypse Virus 开始蔓延,这也让日本政府陷入混乱并丧失身为政府的主要机能,此一事件即后来被称为Lost Christmas 的历史灾害。

  但在鲜为人知的背后却有着另一段的故事,而游戏描写的就是Scrooge与Carol两人在这个时候鲜为人知的另一段大活跃故事。

下载:http://kuai.xunlei.com/d/GRGPOHGTMEFY
密码:四散的尘埃
游戏分级:15+

011f5fc6a7efce1b659c2112af51f3deb68f65a0.jpg

迅雷7 精简助手 v1.0 测试版

本人制作的一款迅雷7精简助手,其支持迅雷7系列的所有版本,程序自动搜索迅雷目录,精简组件,精简下来的内容会自动备份,您可以在addins_backup中找到它们

鉴于此版本为测试版,故需要序列号,前几位评论者可以获得序列号。公测版中将取消序列号系统。

下载地址: http://u.115.com/file/f4d0e0a8b9

ps: 下个版本可能会增加屏蔽广告的…

来自 Android 版 WordPress.

  1. 1
  2. 2
  3. 3