使用WHERE子句或使用应用程序代码过滤结果集是否更好?

时间:2010-02-24 06:11:32

标签: php sql mysql

好的,这是一个简单的问题抽象:

2个变量(male_users和female_users)用于存储2组用户,即男性和女性

  1. 一种方法是使用两个查询来选择它们:
  2. select * from users where gender = 'male'然后将结果存储在male_users

    select * from users where gender = 'female'然后将结果存储在female_users

    1. 另一种方法是只运行一个查询:
    2. 'select * from users'然后循环结果集以过滤程序中的男性用户 php代码片段会像这样:

      $result = mysql_query('select * from users');
      
      while (($row=mysql_fetch_assoc(result)) != null) {
        if ($row['gender'] == 'male'){// add to male_users}
        else if ($row['gender'] == 'female'){// add to female_users}
      }
      

      哪一个更有效并被认为是更好的方法?

      这只是问题的简单说明。真实的项目可能有更大的表格来查询和更多的过滤选项。

      提前感谢!

3 个答案:

答案 0 :(得分:9)

任何应用程序的经验法则都是让数据库执行它做得很好的事情:过滤,排序和加入。

将查询分成他们自己的函数或类方法:

$men = $foo->fetchMaleUsers();
$women = $foo->fetchFemaleUsers();

更新

我使用Steven的PostgreSQL演示了一个全表扫描查询,执行两次单独的索引查询,并使用MySQL模拟它(在实际问题中使用):

模式

CREATE TABLE `gender_test` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `gender` enum('male','female') NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=26017396 DEFAULT CHARSET=utf8

我将性别类型更改为不是VARCHAR(20),因为它对于此列的目的更为现实,我还提供了一个主键,就像您期望在表上而不是任意的DOUBLE值。

未编制索引的结果

mysql> select sql_no_cache * from gender_test WHERE gender = 'male';

12995993 rows in set (31.72 sec)

mysql> select sql_no_cache * from gender_test WHERE gender = 'female';

13004007 rows in set (31.52 sec)

mysql> select sql_no_cache * from gender_test;

26000000 rows in set (32.95 sec)

我相信这不需要解释。

索引结果

ALTER TABLE gender_test ADD INDEX (gender);

...

mysql> select sql_no_cache * from gender_test WHERE gender = 'male';

12995993 rows in set (15.97 sec)

mysql> select sql_no_cache * from gender_test WHERE gender = 'female';

13004007 rows in set (15.65 sec)

mysql> select sql_no_cache * from gender_test;

26000000 rows in set (27.80 sec)

此处显示的结果从根本上与Steven的数据不同。索引查询执行几乎的速度是全表扫描的两倍。这是使用常识列定义的正确索引表。我根本不了解PostgreSQL,但是在Steven的例子中必须有一些重要的错误配置才能显示出类似的结果。

鉴于PostgreSQL比MySQL做得更好的声誉,或者至少和MySQL一样好,我敢说如果使用得当,PostgreSql会表现出类似的性能。

另请注意,在同一台机器上,执行5200万次比较的过度简化的for循环需要额外的7.3秒才能执行。

<?php
$N = 52000000;
for($i = 0; $i < $N; $i++) {
    if (true == true) {
    }
}

我认为给出这些数据的更好方法是显而易见的。

答案 1 :(得分:4)

答案 2 :(得分:0)

如果您有100万用户,您更喜欢(考虑其中一半是男性,一半是女性)

  • 从数据库中获取100万用户?
  • 或仅从DB中获取500k用户?

我想你会回答说你更喜欢只取一半的用户;-)并且,根据条件,如果更复杂,它甚至可能比这还要小。


基本上,获取更少的数据意味着:

  • 少用网络“无用”(即获取即将被丢弃的数据)
  • 使用的内存较少,尤其是在PHP服务器上
  • MySQL服务器上的磁盘访问量可能更少 - 因为从磁盘中获取的数据更少

在一般情况下,我们会尽量避免获取更多必要的数据;即我们将过滤放在数据库端。


当然,这意味着您必须考虑将要放在数据库表中的索引:它们必须满足您将要执行的查询的需要。