2009-07-24 50 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被返回两次,因此至少有一部分返回的是浪费数据库和网络资源。

相关问题