2007-01
02

Wordpress的效率问题似乎一直是议论的热点,今天来看看其中一条SQL语句的效率。

首先将所有插件禁用,并切换为默认模板。 然后按照《WordPress执行效率问题》这篇文章的方法, 在 wp-config.php 中加入

<?php define('SAVEQUERIES', true); ?>

在模板的 footer.php 中加入

<!-- <?php var_dump($wpdb->queries); ?> -->

访问首页,即可从源代码中看到SQL语句。

执行时间最长的是这一条,花了0.02秒:

SELECT DISTINCT * FROM wp_posts  
WHERE 1=1 
  AND post_date_gmt <= '2007-01-02 07:12:59' 
  AND (
    post_status = 'publish' 
    OR
      post_author = 1 
      AND post_status != 'draft' 
      AND post_status != 'static'
  )
  AND post_status != 'attachment' 
GROUP BY  wp_posts.ID  
ORDER BY post_date DESC 
LIMIT 0, 10"

这条语句位于 class.php 的 WP_Query->&get_posts() 函数。

说说这个SQL语句的问题。不妨先来看看 wp_posts 表的结构(省略无关列)。

列名类型索引
IDbigint(20)PRIMARY
post_authorbigint(20)
post_date_gmtdatetime
post_statusenumINDEX
post_namevarchar(200)INDEX

首先是关键字 DISTINCT,DISTINCT的作用是去掉重复的数据, 相当于对选择的列进行 GROUP BY。而这条语句中选择了 * 列,包含了主键列 ID, 每行数据必然不相同,因此 DISTINCT 关键字起不到任何作用, 白白浪费一次排序。

其次是 post_date_gmt 和 post_author 上的比较操作。wp_posts表仅有 ID、post_status 和 post_name 列上有索引,对其他列的比较操作使得mysql不得不访问wp_posts表的所有数据, 影响效率。

然后是 post_status 上的不等于的比较。对索引列使用不等于比较, 会导致数据库不能使用索引(索引只能判断等于关系)。 另外显然已经有了 post_status = 'publish' 的条件, 不必再判断 post_status != 'attachment'。

最后是 GROUP BY wp_posts.ID,仍然是对一个不会重复的列进行 GROUP BY, 毫无意义。

如果不考虑功能损失,将这个 SQL 语句优化为下面这样,则仅需花费0.003秒。

SELECT * FROM wp_posts  
WHERE 1=1 
  AND post_status = 'publish' 
ORDER BY post_date DESC 
LIMIT 0, 10"

使用Apache Bench做测试,优化前平均每个请求的处理时间为 503.125ms,优化后为 478.125ms。



2006-06
13

Oracle管理中常用的SQL语句。
阅读全文 »


2006-06
13

Oracle使用过程中经常会用到的SQL语句。
阅读全文 »


2006-06
02

Oracle中试图对一个子查询进行更新时可能会出现ORA-01779错误。该错误的内容为:

ORA-01779: cannot modify a column which maps to a non-key-preserved table
阅读全文 »

2005-09
27

今天一个朋友问我,一个表有两个字段mac和ip,如何找出所有的mac相同而ip不同的记录?想了半天写出了下面的这个SQL语句。

mysql> select * from ip;
+-----+-----+
| mac | ip  |
+-----+-----+
| abc | 123 |
| def | 456 |
| ghi | 245 |
| abc | 678 |
| def | 864 |
| abc | 123 |
| ghi | 245 |
+-----+-----+
7 rows in set (0.00 sec)

mysql> SELECT  DISTINCT a.mac, a.ip
    -> FROM ip a, ip b
    -> WHERE a.mac = b.mac AND a.ip <> b.ip ORDER BY a.mac;
+-----+-----+
| mac | ip  |
+-----+-----+
| abc | 678 |
| abc | 123 |
| def | 864 |
| def | 456 |
+-----+-----+
4 rows in set (0.00 sec)


2005-06
03

NULL值不等于0,也不等于空,它表示该值不定。

任何运算(加减乘除、字符串连接等)的运算数中包括NULL值时,整个表达式的值即为NULL。使用单行函数对NULL值进行处理,得到的结果也为NULL(NVL等函数除外)。

但是NULL值的布尔运算结果并不一定是NULL,例外的情况为,FALSE AND NULL 结果为FALSE,TRUE OR NULL 结果为TRUE。这是因为在AND运算时只要有一个运算数为FALSE结果即为FALSE,即使另一个运算数为NULL,结果也是一定为FALSE的。反之OR运算中,只要有一个运算数为TRUE,结果即为TRUE。

分组函数均忽略NULL值。

排序时,NULL被看作是最大的值,即正序时NULL显示在最下方,逆序时NULL显示在最上方。

处理NULL值的函数有如下几个:

  • NVL(参数1, 参数2):如果参数1不为NULL,则返回参数1;如果参数1为NULL,则返回参数2
  • NVL2(参数1, 参数2, 参数3):如果参数1不为NULL,则返回参数2;如果参数1为NULL,则返回参数3。该函数的返回值的类型总是与参数2相同,当参数1为NULL时,Oracle会将参数3转换成参数2的数据类型之后再返回。
  • NULLIF(参数1, 参数2) :如果参数1等于参数2,则返回NULL;如果参数1不等于参数2,则返回参数1。
  • COALESCE(参数1, 参数2, ..., 参数n):返回参数1到参数n中第一个不为NULL的值。