ziguzagu.org

RewriteCond で正規表現を使わずにプチ最適化

RewriteCond のサンプルとしてよく見かけるこんな書き方。

RewriteCond %{REQUEST_METHOD} ^GET$

これはこうも書けてこっちのがちょっぴり速い。

RewriteCond %{REQUEST_METHOD} =GET

違いは、文字列の比較を正規表現(ap_regexec)でやるか strcmp でやるかの差。Apache 2.2.4 の該当部分のソース、modules/mappers/mod_rewrite.c(の apply_rewrite_cond 関数)から抜粋。

case CONDPAT_STR_EQ:
    if (p->flags & CONDFLAG_NOCASE) {
        rc = !strcasecmp(input, p->pattern);
    }
    else {
        rc = !strcmp(input, p->pattern);
    }
    break;

default:
    /* it is really a regexp pattern, so apply it */
    rc = !ap_regexec(p->regexp, input, AP_MAX_REG_MATCH, regmatch, 0);

    /* update briRC backref info */
    if (rc && !(p->flags & CONDFLAG_NOTMATCH)) {
        ctx->briRC.source = input;
        ctx->briRC.nsub   = p->regexp->re_nsub;
        memcpy(ctx->briRC.regmatch, regmatch, sizeof(regmatch));
    }
    break;
}

default が正規表現。で、ためしにベンチ。

こんなやつと、

RewriteCond %{REQUEST_METHOD} ^GET$
RewriteCond %{REQUEST_METHOD} !^POST$

こんなやつを、

RewriteCond %{REQUEST_METHOD} =GET
RewriteCond %{REQUEST_METHOD} !=POST

x 10 書いて、最後に

RewriteRule ^/$ /index.html [R,L]

で、Apache のデフォルトのページをとってくるだけ。ベンチは ab でこんくらい。

ab -d -c 10 -n 50000 http://localhost:82/

(環境:coLinux 8.0 / Ubuntu 7.10 / Apache 2.2.4 / CPU PentimuM 1.1 GHz。Apache の設定は apt でいれたときについてくる site-available/default + mod_rewrite ぐらいでほとんど素)

正規表現のほうは、

Concurrency Level:      10
Time taken for tests:   15.550234 seconds
Complete requests:      50000
Failed requests:        0
Write errors:           0
Non-2xx responses:      50003
Total transferred:      25251515 bytes
HTML transferred:       14400864 bytes
Requests per second:    3215.39 [#/sec] (mean)
Time per request:       3.110 [ms] (mean)
Time per request:       0.311 [ms] (mean, across all concurrent requests)
Transfer rate:          1585.76 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   3.2      0      50
Processing:     0    2  48.4      0    5550
Waiting:        0    1  22.8      0    4960
Total:          0    3  48.5      0    5550

で、strcmp のほうが、

Concurrency Level:      10
Time taken for tests:   14.210214 seconds
Complete requests:      50000
Failed requests:        0
Write errors:           0
Non-2xx responses:      50004
Total transferred:      25252020 bytes
HTML transferred:       14401152 bytes
Requests per second:    3518.60 [#/sec] (mean)
Time per request:       2.842 [ms] (mean)
Time per request:       0.284 [ms] (mean, across all concurrent     requests)
Transfer rate:          1735.37 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   3.4      0      40
Processing:     0    1   3.9      0      40
Waiting:        0    1   3.5      0      40
Total:          0    2   4.9      0      40

という結果。実際のところ、完全一致で文字列展開もないパターンの比較なのでちょっぴり速い、という程度でしか差はない。。。

けど「ピークタイムに 0.1ms でも稼ぎたいんじゃ!!」と思っていても思っていなくても、もったいないので、完全一致比較の条件パターンは「=」使いましょう。