2013年2月19日 星期二

[SQL] SQL tuning 奇技淫巧 (in Oracle)

雖然真的很討厭SQL,但是只要從事web開發的多多少少都會碰到,實在是無法避免。最近碰到了SQL從一個table取資料去update另一個table的效能問題,最初的寫法是這樣的:
UPDATE NEW_DATA N
SET N.A_COLUMN =  (   
    SELECT O.A_COLUMN
    FROM OLD_DATA O
    WHERE O.ID = N.ID) 
)
這樣的寫法跑了大概半個小時都還沒跑完(一共4萬多筆資料),最後受不了把他停下來,改成以下寫法:
UPDATE (
    SELECT  N.A_COLUMN NEW_A, 
            O.A_COLUMN OLD_A
      FROM  NEW_DATA N, OLD_DATA O
     WHERE  O.ID = N.ID
)
SET NEW_A = OLD_A
結果不到兩分鐘就跑完了~原因是第二種寫法會先將兩個table依select條件join成一個暫存的view,這個view再用自己的資料對自己做update,而不是像第一種寫法一樣每寫一筆資料之前都要先查詢一次。

Partition

Select ID, GROUP
    From (
        Select  ID,
                GROUP,
                Row_Number() Over (Partition By GROUP Order By Abs(ID) Desc) Sequence
                -- 針對同一個GROUP的資料依ID大小排序,並給定序號
        From DATA
    ) TEMP
WHERE TEMP.SEQUENCE = 1
-- 只取出每個GROUP最大ID的資料

2013年2月16日 星期六

[JS] function - 函數物件

前言

javascript引擎要執行javascript時,會先"預編譯",即對所有宣告的變數及函式進行處理,但要注意的是,在函數中被宣告的local變數只有在函式被呼叫時才會被處理,函數return之後這些變數就會被釋放。


函數的定義

函數有三種定義方式:
1. 以function宣告(ex. function abc(){})
2. 匿名函數(ex.function(){})
3. Function建構函數(ex. var fn = new Function("return true;"))
前面有提到在預編譯時會先處理被宣告的函數及變數,所以第一種的宣告方式或是將匿名函數指定給一個變數時....
var fn = function(){/*Do something*/};
會在預編譯時期先被處理,但在直接執行匿名函數....
(function(){/*Do something*/})();
或是用Function建構函數來建立函數時都會在執行到該行程式碼的時候才會被處理。因為這樣的特性使得我們能用Function來比較動態的宣告函數,但因為必須以字串方式傳入函式的敘述內容(函式中要執行的程式碼),所以相對不好維護,而且因為是動態編譯的,效率也會較差,我們可以用一段程式碼來證明:
var startTime = (new Date()).getTime();
for(var i=0; i<100000; i++){
    function fn(){}
}
var total = (new Date()).getTime() - startTime;
alert("function*100,000 takes "+total); // 62 secs

var startTime = (new Date()).getTime();
for(var i=0; i<100000; i++){
    new Function();
}
var total = (new Date()).getTime() - startTime; // 18991 secs
alert("new Function*100,000 takes "+total);


函數的作用域(scope)

就像上一段所說,因為宣告function會在預編譯時期就被處理,所以函數的作用域是取決於宣告時所在的位置,立即執行函式(IIFE,直接執行匿名函數)也是。但是以Function建構函式所建立的函數作用域是Global。
var a = 1;
function fn(){
    var a=2;
    var fn1 = function(){alert(a);}
    var fn2 = new Function("alert(a)");
    fn1(); //"2"
    fn2(); //"1"
}
fn();


arguments物件

在function中可以使用arguments這個array物件,其中包含了所有被傳入此函數的參數,即使這個函數並不需要任何的輸入,例:
function fn(){
    for(var i in arguments){alert(arguments[i]);}
}
fn(1,2,3,4,5,6,7,8,9);
順帶一提,要如何取得一個函數預定接收幾個參數呢?可以使用function.length


.call() & .apply()

之前剛好寫了一篇關於這兩個方法的文章
這兩個方法能讓function很靈活的視作不同object的屬性來使用,切換不同的scope,用完之後馬上消失,不會真的成為該object的屬性。


別忘了function物件也有屬性

function也是個物件,當然也有自己的屬性。下面的這段程式碼想用迴圈來依次輸出1~10,但這樣的寫法用到了全域變數,缺乏封閉性。
function fn(){
    return x++;
} 
var x = 1;
for(var i=1; i<=10; i++){
    alert(fn());
}
所以我們可以利用函數自己的屬性來暫存這個值
function fn(){
    return fn.x++;
} 
fn.x = 1;
for(var i=1; i<=10; i++){
    alert(fn());
}


閉包(Closure)

在C、JAVA等語言中,當呼叫函數並傳回後,所有的區域變數就會被釋放,即刪除他們所在的堆疊。但在Javascript裡,如果宣告了一個內嵌函數,區域變數將在函數傳回後仍能被存取。我們可以利用這種特性來設計具有封閉及包裹性的閉包架構:
var mod = (function(){
    var d=0;
    var foo=function(){return d;};
    return foo;
})();
alert(mod()); // "0",還是存取得到閉包中的變數
關於Javascript的模組化可看一下之前的這篇文章


2013年2月12日 星期二

[JS] deferred.promise()的應用

今天在看jQuery的.animation()程式碼的時候注意到的。

之前就有稍微研究一下jQuery的deferred物件,今天看到他被用在animation的程式碼裡面,而且是我之前沒學過的用法,於是在這邊筆記一下。
var obj = { speak: function(name){alert(name);} }
    deferred = $.Deferred();
deferred.promise(obj);
obj.done(function(name){obj.speak(name)});
deferred.resolve("Kevin");

After being promised, the object would would be extended with some of the deferred object's function like "done", "fail", "always".

As the above, though the promised object can't resolve it self, but the deferred object who promise it can. And it can even pass an argument on resolving or rejecting it.

The deferred object really helps dealing with asyncronise problems in javascript.


2013年2月11日 星期一

[前端] Responsive Web Design - 自適應網頁設計技巧整理

自己在開發網站前端時往往會希望在任何device上的UX都能呈現到最好,又不想為每種顯示模式特別再寫一份layout,就開始研究RWD,畢竟很多實驗性或是新創網站是沒那麼多成本去特別寫一個mobile版的。

"Responsive Web Design",或"自適應網頁設計"其實比較像是個設計概念,而不是什麼特定技術,但是在實踐他的過程中我們還是需要一些小技巧,以下是到目前為止累積的一點小心得:


1. CSS: width:X%

一般在設計網頁常用的兩欄式、三欄式設計,往往是用固定的欄寬來對side area做定義,但當螢幕寬度小於網頁的總寬度的話就會出現橫向的scroll-bar,這是在行動裝置上所不樂見的,最好的方法是利用比例來做切割,例如1:3的兩欄式就可以利用個別設定他們的寬度為"25%"、"75%"
(但事實上你往往會需要為他們留一點margin,所以比較實際的配置應該是25:1:74之類的)
Fluid 960 GridBootstrap fluid layout 等都是可以拿來現成使用的樣板。


2. CSS: max-width: X%

雖然直接用比例來定義欄位或container的寬度十分方便,但有時候會遇上「寬度100%在小螢幕剛剛好,但在寬螢幕上看就是大的很奇怪」或是「寬度60%在大螢幕剛剛好,但在小螢幕就太小」的這種尷尬情況。這種時候可以用接下來會講到的Media Query來解決,但畢竟要多寫一種css配置實在有點麻煩,畢竟有的時候這只是局部性的小配置罷了。這種令人尷尬的小壞蛋只要用max-width就可以輕鬆的切換寬/窄螢幕下適合的寬度設定!解決的方式如下:
.ding-dong-box{
    width: 480px;
    max-width: 100%;
}
這樣一來只要這個box的container的寬度大於480px,ding-dong-box會維持原樣,而當縮到比480px窄的時候,ding-dong-box也會跟著一起縮小。實際應用可以參看這個網頁試算表格


3. CSS: Media Query

Media Query就是讓瀏覽器判定目前的devise寬度套用不同的css設定,很多前輩都已經寫得很棒了,小弟在這邊就恭敬的附上幾篇連結:
用CSS3的Media Queries進行自適應網頁設計(Responsive Web Design)
Mobile Web 前端技術筆記(二): Media Queries 與 CSS
比較要注意的是,在行動裝置上的配置不能用@media  screen and (max-width: 480px)來達成,
針對行動裝置的偵測必須寫成:@media screen and (max-device-width: 480px)
而Media Query 的最終目的就是要讓layout能在大型裝置的橫向配置和行動裝置的縱向配製作切換。至於這些配置間的不同,可以看這篇文章的介紹:"Responsive Design with CSS3 Media Queries" 或是參考 "Bootstrap fluid layout" 這個template,總之概括來說就是要讓兩欄(ex. 30:70)或三欄(ex. 20:60:20)這種配置可以在行動裝置上切換成縱向的配置(每個區塊的寬度都是100%)


4. align="center" VS style="margin: 0 auto;"

很常見的水平置中問題,除了在外面套一層align屬性為center的container以外,你也可以設定margin為"0 auto",利用margin來平均補齊左右空間達到水平置中的結果。
總而言之,拜託不要再用<center></center>了.....


5. Javascript

放大絕,特殊情形不知道該怎麼解決的時候就用$(window).resize();和$("").css()吧!