编写这个sql语句的推荐方法是什么?

时间:2009-07-24 06:35:14

标签: sql c sqlite

考虑到可读性和性能,有什么更好的格式化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);

8 个答案:

答案 0 :(得分: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,占位符二对应t1。如果您不希望计算符合时间范围的事件(也就是说,您不希望计算在t1时刻结束的事件,或者在时刻{{1}开始的事件}),然后将“t2”和“>=”分别更改为“<=”和“>”。

这是在包含结束时间时写入重叠谓词的标准方法。 条件更简单 - 没有OR术语 - 并且是可靠的。它会更快,因为优化器的工作量较少,可能执行引擎的应用标准较少。 (一个非常好的优化器可能会发现2占位符和6占位符版本的等价,但我不想打赌这样做 - 尤其是因为优化器不能告诉占位符1,3,5将是同样,占位符2,4,6也不会相同;只有在执行该声明时,如果它不愿重新优化,则只能确定。)

答案 1 :(得分:5)

对于初学者,您可以使用BETWEEN而不是&gt; =和&lt; =。这将使查询更多更具可读性,而不会对性能产生任何影响。至于优化性能查询,您应该考虑使用数据库等效的EXPLAIN计划来为您提供有关查询在大部分时间内占用的位置的一些指示。

答案 2 :(得分:3)

StartTime和EndTime都应该被编入索引 - 因为所有的过滤和排序都是基于这些值完成的,这一点很重要。

如果您的SQL引擎支持,我还会使用BETWEEN语句。但是,BETWEEN通常是包容性的(无论如何它都在SQL Server中),因此它可能只适用于您的第一个日期过滤器,因为其他人使用&lt;和&gt;。

答案 3 :(得分:2)

我建议不要使用“SELECT *”,这通常是CPU /时间/消耗比明确列出你想要的字段要多得多,并且对于其他人来说它更具可读性,因为你不必记住哪些是表中包含的字段。

对于BETWEEN,

+1会影响性能,使您的查询更快。

答案 4 :(得分:2)

指定您需要的列,选择*不应在生产代码中使用。通过仅发送您需要的列,性能将得到改善。现在,rowid被返回两次,因此至少你返回的部分内容浪费了数据库和网络资源。

答案 5 :(得分:1)

格式化(换行,缩进,...)对性能没有影响。除非你把毫米(我的意思是数千/数百万不必要的空间)放在空白上,这可能会显着延迟查询传输。编译器将整个查询编译为单个常量。

答案 6 :(得分: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;"

答案 7 :(得分: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&lt; = ts.end。如果您有明确定义的参数,应用程序逻辑通常可以保存数据库引擎的工作。