Mar 08
我利用前兩天的空閒時間寫了個 PHP 的小程式,運用 PHP 的 PDO 元件,對 MySQL 進行小測試。
Server 作業系統與硬體:
- 作業系統:FreeBSD 8.0-RELEASE
- CPU:Intel(R) Pentium(R) 4 CPU 3.00GHz (3042.62-MHz 686-class CPU),Hyper-Threading 開啟
- RAM:2G DDR2 800
- 放資料庫的 HDD:WDC WD800JB-00JJA0,UDMA 100
MySQL 5.1.44 的設定(/etc/my.cnf):
# defult setting (maybe changed)
key_buffer_size = 128M
max_allowed_packet = 4M
table_open_cache = 4096
sort_buffer_size = 1M
net_buffer_length = 8K
read_buffer_size = 256K
read_rnd_buffer_size = 512K
myisam_sort_buffer_size = 8M
# added for tunning by Joe Horn
skip-name-resolve
connect_timeout = 60
join_buffer_size = 1M
max_connect_errors = 10000
max_connections = 100
max_heap_table_size = 1G
query_cache_size = 16M
slave_net_timeout = 30
sync_binlog=1
thread_cache_size = 512
thread_concurrency = 8
tmp_table_size = 1G
table_definition_cache = 512
# choose one ( depend on query amount )
#concurrent_insert=2
low_priority_updates=1
這台機器跑 Super Smack 的結果:
# super-smack -d mysql update-select.smack 80 1000
Query Barrel Report for client smacker
connect: max=14ms min=1ms avg= 4ms from 80 clients
Query_type num_queries max_time min_time q_per_s
select_index 80000 101 6 717.91
update_index 80000 108 1 717.91
我用測試程式產生了一百萬筆資料的 MyISAM table,各種測試各循環 1000 次,產生如下的測試結果(後面的數字單位是秒):
SELECT BY PK_COL WITH_QUERY_CACHE: 0.058
SELECT BY PK_COL WITHOUT_QUERY_CACHE: 0.062
SELECT BY PK_COL LIMIT WITH_QUERY_CACHE: 0.058
SELECT BY PK_COL LIMIT WITHOUT_QUERY_CACHE: 0.062
SELECT BY UNIQUE_COL WITH_QUERY_CACHE: 0.058
SELECT BY UNIQUE_COL WITHOUT_QUERY_CACHE: 0.062
SELECT BY UNIQUE_COL LIMIT WITH_QUERY_CACHE: 0.058
SELECT BY UNIQUE_COL LIMIT WITHOUT_QUERY_CACHE: 0.062
SELECT BY INDEX_COL WITH_QUERY_CACHE: 0.058
SELECT BY INDEX_COL WITHOUT_QUERY_CACHE: 0.061
SELECT BY INDEX_COL LIMIT WITH_QUERY_CACHE: 0.058
SELECT BY INDEX_COL LIMIT WITHOUT_QUERY_CACHE: 0.063
SELECT BY COL WITH_QUERY_CACHE: 0.786
SELECT BY COL WITHOUT_QUERY_CACHE: 0.063
SELECT BY COL LIMIT WITH_QUERY_CACHE: 0.059
SELECT BY COL LIMIT WITHOUT_QUERY_CACHE: 0.062
UPDATE BY PK_COL WITH_QUERY_CACHE: 1.139
UPDATE BY PK_COL WITHOUT_QUERY_CACHE: 1.199
UPDATE BY PK_COL LIMIT WITH_QUERY_CACHE: 0.125
UPDATE BY PK_COL LIMIT WITHOUT_QUERY_CACHE: 0.142
UPDATE BY UNIQUE_COL WITH_QUERY_CACHE: 2.734
UPDATE BY UNIQUE_COL WITHOUT_QUERY_CACHE: 1.203
UPDATE BY UNIQUE_COL LIMIT WITH_QUERY_CACHE: 0.147
UPDATE BY UNIQUE_COL LIMIT WITHOUT_QUERY_CACHE: 0.163
UPDATE BY INDEX_COL WITH_QUERY_CACHE: 1.183
UPDATE BY INDEX_COL WITHOUT_QUERY_CACHE: 1.063
UPDATE BY INDEX_COL LIMIT WITH_QUERY_CACHE: 0.138
UPDATE BY INDEX_COL LIMIT WITHOUT_QUERY_CACHE: 0.154
UPDATE BY COL WITH_QUERY_CACHE: 4704.859
UPDATE BY COL WITHOUT_QUERY_CACHE: 4641.191
UPDATE BY COL LIMIT WITH_QUERY_CACHE: 0.156
UPDATE BY COL LIMIT WITHOUT_QUERY_CACHE: 0.167
根據測試結果,大概可以看到出以下幾個要點:
- 根據第 21 行與 22 行的差異看來,MySQL Query cache 還是有點用處,不過效用不大。
- 根據第 13 行與第 29 行的結果看來,有沒有設定 Primary Key、UNIQUE、INDEX 的影響不小。
- 根據 UPDATE 語法的測試結果看來,有沒有 LIMIT 頗重要。
Technorati Tags: FreeBSD, INDEX, LIMIT, MySQL, PDO, PHP, Primary Key, Query Cache, Super Smack, UNIQUE
Tags:
FreeBSD ,
INDEX ,
LIMIT ,
MySQL ,
PDO ,
PHP ,
Primary Key ,
Query Cache ,
Super Smack ,
UNIQUE
(Visited 213 times)
Mar 07
這是前陣子在寫 Plurk Bot 時發現的問題。
因為 FeedBurner 已經被 Google 買下了。
所以,FeedBurner 會以「http://feedproxy.google.com/.....」這種 URL 進行 HTTP 重新導向,使瀏覽器連結到「http://原始URL/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A......」這種頁面。
若是部落客用 FeedBurner 把放在 Xuite 上面的部落格 RSS/Atom feed 燒起來,而訂閱者透過 feedproxy.google.com 連結到文章頁面時,得到 HTTP 400 Error 的頁面(只有第一次被重新導向時,是正常的)。
會得到 HTTP 400 Error 頁面的原因是...
經過第一次的瀏覽後,瀏覽器的 cookie 被塞入兩個值,而 Xuite 無法正確解析瀏覽器的 cookie。

目前使用者自行排除問題的方式是拒絕 Xuite 存取瀏覽器的 cookie。
Technorati Tags: cookie, FeedBurner, Google, Xuite
Tags:
cookie ,
FeedBurner ,
Google ,
Xuite
(Visited 193 times)
Mar 02
在 1 月底,我開始使用 FreeBSD Port Tools 來製作/修改 FreeBSD ports。
因為太好用了,使得我在一個月左右時間內,整整送了 10 個 FreeBSD PR(我知道這種量不值一提,但對我來說,這是目前為止的尖峰值)。
對 FreeBSD ports 有興趣的人,請先詳讀一下這個討論串。
針對 FreeBSD Port Tools 的使用,大概要注意的是:
- 要送出前,請先用 port test 測試過,並記得用 -- 參數來測試所有的 make 參數與選項。
- 修改 ports,但只是 patch,不是版本更新時,請用 port submit -m change,並記得修改 Synopsis。
- 對 ports 進行版本更新時,請用 port submit -m update。
- 製作新的 ports 時,請用 port submit -m new。
至於 FreeBSD ports 的部份,大概要注意這些:
- 如果是 PHP Web systems/projects,要先下載後解開,花點時間檢查該系統需要哪些 PHP extensions。可以參考 PHP 的 Function Reference,例如:mbstring 可以用 grep -r "mb_*" [PHP_PROJECT_ROOT_DIR]。
- 如果要在安裝後顯示的 pkg-message,或是 pkg-plist 帶入變數,建議在 [PORT_DIRECTORY]/files 放 pkg-message.in 或 pkg-plist.in 這種檔案。
- 儘量在 Makefile 使用變數,主要(常用)的變數可以參考 /usr/ports/Mk/bsd.port.mk,其他的請參考 /usr/ports/Mk/ 底下的其他檔案。
由於我還算是新手小嫩咖,目前只能提供以上的心得(順便留個筆記)... orz
Technorati Tags: FreeBSD, ports, porttools
Tags:
FreeBSD ,
ports ,
porttools
(Visited 437 times)
Feb 02
這幾天,我的噗浪河道上,除了 Apple iPad 之外,也出現了一些關於 CNNIC 根憑證的噗。
基於中國大陸政府的黑暗與邪惡,以及中國網路界的「和諧」作風,我決定把 CNNIC 的根憑證移除掉,順便把移除方法貼出來。
- IE(Internet Explorer):

- Firefox(聽說 3.6 有。因為我在用的附加元件尚未完全相容,所以我還在用 3.5.7):

2010/02/02 23:37 UPDATE
另有 MacOS 與 Linux 的移除教學文,有需要的請參考以下連結:
Technorati Tags: CNNIC, Firefox, IE, Internet Explorer, root certificate
Tags:
CNNIC ,
Firefox ,
IE ,
Internet Explorer ,
root certificate
(Visited 2686 times)
Jan 09
有安裝 Gallery 2 作為相簿系統的人可能跟我一樣,會在 Apache 的 error log 裡面看到一大串如下的 log:
PHP Notice: Undefined index: sfPhotosRecursiveLimit in [Gallery目錄]/modules/rss/SimpleRender.inc on line 78
追了一下程式,發現是變數沒處理好。
於是,我修改了 modules/rss/SimpleRender.inc,加了以下這段程式碼處理變數:
if ( !isset($params['sfPhotosRecursiveLimit']) ) {
$params['sfPhotosRecursiveLimit'] = $params['sfPhotosRecurseLimit'];
}
修改過後的某個片段長這樣:
$params['feedDate'] = $params['sfDate'];
if ( !isset($params['sfPhotosRecursiveLimit']) ) {
$params['sfPhotosRecursiveLimit'] = $params['sfPhotosRecurseLimit'];
}
/* apply defaults */
跟我一樣,覺得那些 log 很礙眼的,就參考一下吧。
我把 patch 一併貼到官方論壇了(Problem fix for RSS module),不知道會不會被採用就是了。
Technorati Tags: error, Gallery, RSS
Tags:
error ,
Gallery ,
RSS
(Visited 1491 times)
Jan 08
昨天,FreeBSD 官方發布了三個 Security Advisories:
根據 Advisories 內容,我原本打算透過以下的步驟作 patch:
- cd /usr/src && make update
- cd /usr/src/lib/bind && make obj && make depend && make && make install
- cd /usr/src/usr.sbin/named && make obj && make depend && make && make install
- cd /usr/src/usr.sbin/ntp/ntpd && make obj && make depend && make && make install
- cd /usr/src && make kernel
- [REBOOT]
但是,進行到第 4 個步驟(FreeBSD-SA-10:02.ntpd 的編譯階段),就出現了如下的 message:
make: don't know how to make /usr/obj/usr/src/usr.sbin/ntp/ntpd/../libparse/libparse.a. Stop
找了一些討論後,我在這個討論串裡看到好幾種作法。
幾經嘗試,我最終在 FreeBSD 8.0-RELEASE-p1 amd64 用以下這個作法順利編譯成功:
- cd /usr/src/usr.sbin/ntp
- rm -rf /usr/obj/*
- make obj && make depend && make && make install
有相同問題(狀況)的人可以參考看看。
Technorati Tags: FreeBSD, patch, Security Advisories
Tags:
FreeBSD ,
patch ,
Security Advisories
(Visited 1651 times)
Jan 07
Javascript 提供了 For ... In ... ,我用的還蠻高興的(雖然我很少撰寫 Javascript)。
今天遇到某種特殊需求,我才發現這個迴圈語法並非萬能。
從 array 裡隨機挑出不重複的值有兩種情況,一種很單純,For ... In ... 迴圈可以處理的很好:
var fruits = ["Banana", "Orange", "Apple", "Mango"];
var x;
while(fruits.length > 0) {
var r = Math.floor( Math.random() * fruits.length );
var n = fruits[r];
document.write("Choosen[" + r + "]: " + n + "<br />");
document.write("Array: " + fruits + "<br />");
for(x in fruits) {
if (fruits[x] == n) {
fruits.splice(x, 1);
}
}
}
若是 array 裡面已經存在重複的值,而且 array 的資料的來源不方便控制(例如是 HTML 裡面的 li 物件),For ... In ... 這種方便的迴圈語法就必須放棄,改用傳統的 for 迴圈:
var fruits = ["Banana", "Banana", "Orange", "Orange", "Banana", "Apple", "Apple", "Orange", "Mango"];
var i=0;
while(fruits.length > 0) {
var r = Math.floor( Math.random() * fruits.length );
var n = fruits[r];
document.write("Choosen[" + r + "]: " + n + "<br />");
document.write("Array: " + fruits + "<br />");
for(i=0; i<fruits.length; i++) {
if (fruits[i] == n) {
fruits.splice(i, 1);
i--;
}
}
}
Technorati Tags: array, For loop, Javascript, random
Tags:
array ,
For loop ,
Javascript ,
random
(Visited 1928 times)
Jan 04
前陣子,在工作上剛好需要對 wav 檔案格式進行判定,可是 NAudio 製作出來的格式用來作判斷又有錯誤,所以土法煉鋼寫了一個小 class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
public class Wave
{
public struct Format
{
public String FileName = String.Empty;
public Boolean PCM = false;
public uint Channel = 0;
public uint SampleRate = 0;
public uint BitsPerSample = 0;
public uint ByteRate = 0;
public uint BlockAlign = 0;
};
private Format _fmt;
private void fillUp()
{
_fmt.ByteRate = _fmt.Channel * _fmt.SampleRate * _fmt.BitsPerSample / 8;
_fmt.BlockAlign = _fmt.Channel * _fmt.BitsPerSample / 8;
}
public Format getType(String fileName)
{
_fmt.FileName = fileName;
try
{
FileStream fs = File.OpenRead(@fileName);
Byte[] readTmp = new Byte[36];
fs.Read(readTmp, 0, 36);
fs.close();
if (BitConverter.ToUInt16(readTmp, 20) == 1)
{
_fmt.PCM = true;
}
_fmt.Channel = BitConverter.ToUInt16(readTmp, 22);
_fmt.SampleRate = BitConverter.ToUInt32(readTmp, 24);
_fmt.BitsPerSample = BitConverter.ToUInt16(readTmp, 34);
fillUp();
}
catch (Exception e)
{
Console.WriteLine("Wave.getType(fileName) Error : " + e.ToString());
}
return _fmt;
}
}
- 檢查 FileName 是否為空字串,就知道是否成功呼叫 getType() 。
- 檢查 PCM 是否為 true,就知道該檔案是不是 PCM 格式的 wav 檔。
- wav 檔播放的時間會等於 ByteRate。
Technorati Tags: .NET, Audio, C#, file, NAudio, PCM, wav
Tags:
.NET ,
Audio ,
C# ,
file ,
NAudio ,
PCM ,
wav
(Visited 1679 times)
Dec 10
我們在開發 PHP 專案時,時常會把一些常用變數放在某個 PHP 檔案,接著用 require()、require_once()、incluce()、include_once() 等函式將之引入。
若系統目錄很複雜,就會在很多檔案裡面看到類似這樣的語法:
require_once('../../Config.php');
然而,當這種系統必須變動目錄結構與檔案所在目錄時,開發人員就得額外多花些時間來更改上述之程式碼。
其實,PHP 的設定檔中,有個很少被注意到的變數,就是 auto_prepend_file 。
假設目前有個 PHP 專案,專案根目錄之系統絕對路徑為 /var/www/html/Project,
共用設定檔為 /var/www/html/Project/Config.php 。
我們可以在 /var/www/html/Project 下建立 .htaccess 檔案,內容如下:
php_value auto_prepend_file "/var/www/html/Project/Config.php"
而 /var/www/html/Project 目錄下所有的檔案,以及所有子目錄中的檔案都會自行引入 /var/www/html/Project/Config.php 。
PS. 由於 auto_prepend_file 的設定是透過 require() 來實作,使用這種方法要特別注意以下兩點:
- 一旦設定了 auto_prepend_file ,該檔案就必須要存在,否則就會有 error ,導致該目錄下的所有 PHP 檔案無法正常執行。
- include_path 會影響 auto_prepend_file。
Technorati Tags: auto_prepend_file, htaccess, include, include_once, PHP, php_value, require, require_once
Tags:
auto_prepend_file ,
htaccess ,
include ,
include_once ,
PHP ,
php_value ,
require ,
require_once
(Visited 2661 times)
Nov 20
幾天前,跟 Solaris 叔叔 談到 MySQL 的 ENUM,回家後上網找了些資料,剛好找出了一些使用 MySQL 時,與效能有關的 tips。
稍微整理過後,放在這裡:
- 善用 EXPLAIN SELECT 分析 SQL statement,以下列舉狀態解讀:
| EQ_REF |
一對一比對 |
| REF |
一對多比對 |
| RANGE |
特定範圍的資料會被傳回 |
| INDEX |
使用 INDEX 裡的資料 |
| ALL |
對整個 TABLE 作掃瞄(最差) |
- 善用 INDEX,以這個 SQL statement 為例:
SELECT `col_a`
FROM `table_a` LEFT JOIN `table_b`
ON `table_a`.`col_b` = `table_b`.`col_c`
WHERE `col_d` = ....;
-- SELECT 的欄位不需 INDEX,ex: `col_a`。
-- JOIN 的欄位需要 INDEX,ex: `table_a`.`col_b` 與 `table_b`.`col_c`。
-- WHERE 的欄位需要 INDEX,ex: `col_d`。
- 儘量使用固定大小的欄位,MyISAM 搜尋固定大小欄位比較快;也就是說,能用 CHAR 就別用 VARCHAR。
- 儘量將欄位指定為 NOT NULL。
- ENUM 格式的欄位,資料處理速度很快(實測結果在這)。
- 不要取不需要的資料,下面這種語法就是不好的例子:
SELECT * ...
- 把 BLOB 與 TEXT 拆開,減少 MySQL 開啟單一大檔(table 資料檔案過大)的機會。
- JOIN 用的欄位資料格式最好是相同的,以免 MySQL 作 FULL TABLE SCAN。
- 使用 LIKE 時,避免把 % 放在字串開頭,以免 INDEX 利用率不佳。
-- 下列這種語法無法利用 INDEX
SELECT ... WHERE `col` LIKE '%string%';
-- 下列這種語法會利用 INDEX
SELECT ... WHERE `col` LIKE 'string%';
- 注意 WHERE 子句內的運算式。
-- 下列這種語法會使用 INDEX,速度快。
SELECT ... WHERE `col` < 100 / 10;
-- 下列這種語法會導致 FULL TABLE SCAN,速度慢。
SELECT ... WHERE `col` * 10 < 100;
Technorati Tags: BLOB, CHAR, ENUM, EXPLAIN, INDEX, MyISAM, MySQL, NOT NULL, performance, TEXT, VARCHAR
Tags:
BLOB ,
CHAR ,
ENUM ,
EXPLAIN ,
INDEX ,
MyISAM ,
MySQL ,
NOT NULL ,
performance ,
TEXT ,
VARCHAR
(Visited 3443 times)
Recent Comments