2009-07-24 82 views
2

考慮到可讀性和性能,更好的方式來格式化後面的sql語句。謝謝。什麼是寫這個SQL語句的推薦方法?

sql = (char *)" SELECT * ,rowid FROM tblEvent_basic " 
        " WHERE " 
        " service_id = ? AND " 
        " (" 
        " (start_time >= ? AND start_time <= ?) OR " 
        " (end_time > ? AND end_time <?) OR " 
        " (start_time < ? AND end_time > ?)" 
        ")" 
        " ORDER by start_time ASC"; 

編輯: 1.sqlite3數據庫引擎;使用C API;在MIPS24K 250M嵌入式CPU上運行。

2.第2,4,6參數相同,與第3,5,7條相同。

rc = sqlite3_bind_int(sql_stmt,1,service_id); 
    rc = sqlite3_bind_text(sql_stmt,2,ts.start, 5, SQLITE_TRANSIENT); 
    rc = sqlite3_bind_text(sql_stmt,3,ts.end , 5, SQLITE_TRANSIENT); 
    rc = sqlite3_bind_text(sql_stmt,4,ts.start, 5, SQLITE_TRANSIENT); 
    rc = sqlite3_bind_text(sql_stmt,5,ts.end , 5, SQLITE_TRANSIENT); 
    rc = sqlite3_bind_text(sql_stmt,6,ts.start, 5, SQLITE_TRANSIENT); 
    rc = sqlite3_bind_text(sql_stmt,7,ts.end , 5, SQLITE_TRANSIENT); 
+0

您正在使用哪種查詢引擎?如果我們知道,我們可以提供更具體的建議。 – SqlRyan 2009-07-24 06:41:02

+0

這是C/C++嗎?你可以使用一些反斜槓 - 換行符來截斷這個字符串,並保存一些引號。 – maxwellb 2009-07-24 06:41:19

+0

你能指出哪些參數是相同的嗎? (我猜OR中的第三個表達式與前兩個參數具有相同的參數) – 2009-07-24 06:50:50

回答

6

你的時間條件目前:

  " (start_time >= ? AND start_time <= ?) OR " 
      " (end_time > ? AND end_time <?) OR " 
      " (start_time < ? AND end_time > ?)" 

馬上就可以提高一些空間可讀性(以固定寬度字體):

  " (start_time >= ? AND start_time <= ?) OR " 
      " (end_time > ? AND end_time < ?) OR " 
      " (start_time < ? AND end_time > ?)" 

而且從評論中,我們知道,同樣的值將被傳遞給佔位符1,3,5,並且不同的值將被傳遞給佔位符2,4,6(但它們也都獲得相同的值)。此外,如果我們調用那些時間t1t2,那麼我們可以假設t1 <= t2

那麼,這個標準是尋找什麼?

  • 開始時間落在範圍t1..t2
  • 結束時間落在t1..t2
  • 開始時間比T1和結束時間早的範圍較T2

這是寫入硬盤的方式的重疊標準 - 它應改爲:

  "(start_time <= ? AND end_time >= ?)" 

除了一個佔位符,對應這裏到t2,佔位符2對應於t1。如果您不希望計數符合時間範圍的事件(也就是說,您不想計算在t1時刻結束的事件或在t2時刻開始的事件),請更改'>= '和'<='分別轉換爲'>'和'<'。

這是在包含結束時間時編寫重疊謂詞的標準方式。 條件要簡單得多 - 沒有或術語 - 並且可靠。優化器的工作量會更少,執行引擎可能會有更少的標準適用。 (一個非常好的優化器可能會發現2位佔位符和6位佔位符版本的等價性,但我不打算這樣做 - 至少因爲優化器不能告訴佔位符1,3,5將是相同,也不佔用2,4,6的佔位符;只有在執行語句時重新優化才能確定。)

5

對於初學者,您可以使用BETWEEN而不是> =和< =。這會使查詢更具可讀性,而不會對性能產生任何影響。就優化查詢性能而言,您應該考慮使用數據庫的EXPLAIN計劃的等價物,以便爲您提供有關查詢大部分時間花在何處的指示。

+3

EXPLAIN上的+1。但是,只有`start_time`範圍是包容的,所以它不會提高可讀性。 – Thorarin 2009-07-24 07:37:14

3

StartTime和EndTime都應該被編入索引 - 因爲所有的過濾和排序都是基於這些值完成的,所以這很重要。

如果你的SQL引擎支持它,我還會使用BETWEEN語句。但是,BETWEEN通常是包容性的(它始終在SQL Server中),所以它可能只適用於您的第一個日期過濾器,因爲其他人使用<和>。

2

我建議不要使用「SELECT *」,這通常是CPU /時間/除了明確地列出你想要的字段外,更容易讀取,因爲你不必記住哪些是表中包含的字段。

+1爲BETWEEN它會影響性能,使您的查詢更快。

+0

BETWEEN如何使查詢更快? – Thilo 2009-07-24 06:54:30

0

嗯...首先,在源代碼中沒有硬編碼的查詢。但是,如果你真的需要,請檢查你選擇的編程語言是否支持多行字符串或塊(或任何你可能稱之爲的)。例如,在Ruby中:

sql = <<BLOCK 

SELECT * ,rowid FROM tblEvent_basic 
WHERE 
service_id = ? AND 
(
(start_time >= ? AND start_time <= ?) OR 
(end_time >= ? AND end_time <?) OR 
(start_time < ? AND end_time > ?) 
) 
ORDER by start_time ASC; 

BLOCK 

或C#:

sql = @"SELECT * ,rowid FROM tblEvent_basic 
WHERE 
service_id = ? AND 
(
(start_time >= ? AND start_time <= ?) OR 
(end_time >= ? AND end_time <?) OR 
(start_time < ? AND end_time > ?) 
) 
ORDER by start_time ASC;" 
+1

我讀過一些查詢優化器實際上在文字查詢而不是參數化查詢時更高效。我曾經閱讀過關於Oracle的這個。沒有驗證它,但它是思考的食物。可能與緩存機制有關? – maxwellb 2009-07-24 06:48:48

+0

這裏提出的改變(將SQL從源代碼中移出)與使它或多或少的文字無關。在這兩種情況下,它都是用綁定變量完全參數化的。至於文字查詢有時更高效,如果數據存在重大偏差,則這可能是真實的,並且使用文字檢查直方圖信息可導致比通用版本更有效的查詢計劃。 – Thilo 2009-07-24 06:58:46

1

格式化(換行符,縮進,...)將會對性能沒有影響。除了如果你把噸(我的意思就像數千/數百萬個不必要的空間)的空白,可以顯着延遲查詢transmision。無論如何,編譯器將整個查詢編譯爲一個常量。

0

您是否對參數施加了任何限制?如果您有使規格以雙倍列出的約束條件,您還可以通過刪除不必要的參數來優化查詢。

比如,查詢在邏輯上等同於:

"SELECT *,rowid FROM tblEvent_basic WHERE service_id = ? AND (\ 
    end_time != ? AND \ 
    end_time > ?) \ 
ORDER BY start_time ASC;" 

rc = sqlite3_bind_int(sql_stmt,1,service_id); 
rc = sqlite3_bind_text(sql_stmt,2,ts.end, 5, SQLITE_TRANSIENT); 
rc = sqlite3_bind_text(sql_stmt,3,ts.start, 5, SQLITE_TRANSIENT); 

..與ts.start < = ts.end的假設。如果您有明確定義的參數,應用程序邏輯通常可以保存數據庫引擎的工作。

2

指定您需要的列,選擇*不應在生產代碼中使用。通過只發送你需要的列,性能會提高。現在,rowid被返回兩次,因此至少有一部分返回的是浪費數據庫和網絡資源。

相關問題