什么更快? SQL 使用通配符和 OR 进行查询,还是使用 php 循环进行过滤的全面查询?
What is faster? SQL query with wildcards and ORs, or catch-all query with php loop for filtering?
我是 运行 单个 table 的查询。我需要最终结果是一个行数组,其中当前用户被列为数据库行记录的消息的参与者。两个参与者列是 staff
和 clients
,并且包含用户 ID and/or 角色名称的序列化数组(例如,a:3:{i:0;s:8:"staffman";i:1;s:3:"203";i:2;s:3:"170";}
)。
尝试在 SQL 查询中过滤掉所有当前用户的所有不匹配项,或者执行一个包罗万象的查询(可能在几百行上),然后循环会更快吗?通过他们过滤掉用户不是参与者的那些?
SQL 选项:
$query = "SELECT * FROM ".self::$messages;
if($is_client) $query .= " WHERE type = 'clients'";
elseif($is_staff) $query .= " WHERE type = 'staff' AND (staff LIKE '%\"".$user->ID."\"%' OR staff LIKE 'staff\"%')";
elseif(!$is_admin)
{
$query .= " WHERE type = 'staff' AND (staff LIKE '%\"".$user->ID."\"%' OR staff LIKE 'staff\"%' OR staff LIKE 'clientman%'";
if($is_staffman) $query .= " OR staff LIKE 'staffman%'";
if($is_accountant) $query .= " OR staff like 'accountant%'";
$query .= ")";
}
$query .= " ORDER BY updated DESC";
循环选项:
$col = $is_client ? 'clients' : 'staff';
$query = "SELECT * FROM ".self::$messages." WHERE type = {$col} ORDER BY updated DESC";
// do the query, then check if there are results. if results...
foreach($results as $msg)
{
if(empty($msg->$col)) continue;
$users = unserialize($msg->$col);
if($is_client)
{
if(!in_array($user->ID, $users) && !in_array('client', $users)) continue;
}
elseif(!$is_admin && $msg->created_by != $user->ID)
{
if(!in_array($user->ID, $users))
{
if(!in_array('staff', $users))
{
if(!$is_clientman || !in_array('clientman', $users))
{
if(!$is_staffman || !in_array('staffman', $users))
{
if(!$is_accountant || !in_array('accountant', $users)) continue;
}
}
}
}
}
// match found, do stuff with it here
}
在这种情况下,您应该始终使用 SQL 选项。
$query = "SELECT * FROM ".self::$messages;
if($is_client) $query .= " WHERE type = 'clients'";
elseif($is_staff) $query .= " WHERE type = 'staff' AND (staff LIKE '%\"".$user->ID."\"%' OR staff LIKE 'staff\"%')";
elseif(!$is_admin)
{
$query .= " WHERE type = 'staff' AND (staff LIKE '%\"".$user->ID."\"%' OR staff LIKE 'staff\"%' OR staff LIKE 'clientman%'";
if($is_staffman) $query .= " OR staff LIKE 'staffman%'";
if($is_accountant) $query .= " OR staff like 'accountant%'";
$query .= ")";
}
$query .= " ORDER BY updated DESC";
为什么?
1.See 通过 WHERE clause.There 过滤,您已经获得更少的记录(仅需要那些),获取所有记录并在 php 中过滤是没有意义的。
2.See 管理 PHP 中的代码很头疼,因为它变得复杂了。
3.Less no.of 行。
4.It 大部分时间由 SQL 管理,php 逻辑会使其变慢。
我接受了上面的答案,因为它是对我提出的问题的明确而明确的答案。但是,Stuart(在评论中)建议我尝试规范化我的结构,而不是使用 LIKES 等扫描序列化数组。这就是我所做的。
我没有以与 messages
table 相同的 table 序列化形式保存我的参与者数组,而是创建了一个名为 message_recipients
的新 table只有三列 (id,mid,user)
,其中 mid
指的是 messages
table 中的 id
列,user
存储个人用户 ID或角色名称。
所以最棘手的部分(实际上并不是那么棘手)是如何在用户更改给定消息的允许收件人时管理从 message_recipients
table 添加和删除行。 (在表单中,他们有两个多选下拉列表——一个用于员工,一个用于客户)。
下面是我管理 updated/changing 参与者部分的方式:
对于每个领域(员工和客户),我将两个数组传递给我的函数,一个是新参与者,一个是旧参与者。 (如果正在创建消息,那么旧的参与者数组就是空的。)
然后是函数(实际工作基本上就四行):
public function update_participants($mid = false, $new_staff = array(), $old_staff = array(), $new_clients = array(), $old_clients = array())
{
global $wpdb;
if(empty($mid)) return array();
$add = array_filter(array_unique(array_merge(array_diff($new_staff, $old_staff), array_diff($new_clients, $old_clients))));
$delete = array_filter(array_unique(array_merge(array_diff($old_staff, $new_staff), array_diff($old_clients, $new_clients))));
if(!empty($add)) $wpdb->query("INSERT INTO ".self::$participants." (mid,user) VALUES(".$mid.",\"".implode("\"),(".$mid.",\"", $add)."\")");
if(!empty($delete)) $wpdb->query("DELETE FROM ".self::$participants." WHERE mid = {$mid} AND user IN (\"".implode("\", \"", $delete)."\")");
return array('added'=>$add, 'deleted'=>$delete);
}
然后我 return 添加或删除的结果数组,所以我可以在我的电子邮件通知中使用它。
那么,既然我们已经规范化了,那么查询 table 以获取当前用户参与其中的所有消息的原始问题就变得更快更简单了:
$query = 'SELECT DISTINCT a.* FROM '.self::$messages.' a, '.self::$participants.' b';
if(!$is_admin)
{
$query .= ' WHERE (b.user = '.$user->ID;
if($is_client) $query .= ' OR b.user = "client"';
elseif($is_staff) $query .= ' OR b.user = "staff"';
else
{
if($is_clientman) $query .= ' OR b.user = "clientman"';
if($is_staffman) $query .= ' OR b.user = "staffman"';
if($is_accountant) $query .= ' OR b.user = "accountant"';
$query .= ' OR a.created_by = '.$user->ID;
}
$query .= ') AND b.mid = a.id';
}
$query .= ' ORDER BY a.updated DESC';
管理员可以得到所有信息,而其他人只会收到在参与者 table 中找到他们的用户 ID 或他们的用户角色的任何消息。 (有些角色有多个角色,因此是三重 if
语句,而不是 elseifs
。
我已经对不同用户的每一种可能配置进行了测试。奇迹般有效。
没有 LIKE,没有通配符,也没有 PHP 循环。
感谢大家的帮助。
我是 运行 单个 table 的查询。我需要最终结果是一个行数组,其中当前用户被列为数据库行记录的消息的参与者。两个参与者列是 staff
和 clients
,并且包含用户 ID and/or 角色名称的序列化数组(例如,a:3:{i:0;s:8:"staffman";i:1;s:3:"203";i:2;s:3:"170";}
)。
尝试在 SQL 查询中过滤掉所有当前用户的所有不匹配项,或者执行一个包罗万象的查询(可能在几百行上),然后循环会更快吗?通过他们过滤掉用户不是参与者的那些?
SQL 选项:
$query = "SELECT * FROM ".self::$messages;
if($is_client) $query .= " WHERE type = 'clients'";
elseif($is_staff) $query .= " WHERE type = 'staff' AND (staff LIKE '%\"".$user->ID."\"%' OR staff LIKE 'staff\"%')";
elseif(!$is_admin)
{
$query .= " WHERE type = 'staff' AND (staff LIKE '%\"".$user->ID."\"%' OR staff LIKE 'staff\"%' OR staff LIKE 'clientman%'";
if($is_staffman) $query .= " OR staff LIKE 'staffman%'";
if($is_accountant) $query .= " OR staff like 'accountant%'";
$query .= ")";
}
$query .= " ORDER BY updated DESC";
循环选项:
$col = $is_client ? 'clients' : 'staff';
$query = "SELECT * FROM ".self::$messages." WHERE type = {$col} ORDER BY updated DESC";
// do the query, then check if there are results. if results...
foreach($results as $msg)
{
if(empty($msg->$col)) continue;
$users = unserialize($msg->$col);
if($is_client)
{
if(!in_array($user->ID, $users) && !in_array('client', $users)) continue;
}
elseif(!$is_admin && $msg->created_by != $user->ID)
{
if(!in_array($user->ID, $users))
{
if(!in_array('staff', $users))
{
if(!$is_clientman || !in_array('clientman', $users))
{
if(!$is_staffman || !in_array('staffman', $users))
{
if(!$is_accountant || !in_array('accountant', $users)) continue;
}
}
}
}
}
// match found, do stuff with it here
}
在这种情况下,您应该始终使用 SQL 选项。
$query = "SELECT * FROM ".self::$messages;
if($is_client) $query .= " WHERE type = 'clients'";
elseif($is_staff) $query .= " WHERE type = 'staff' AND (staff LIKE '%\"".$user->ID."\"%' OR staff LIKE 'staff\"%')";
elseif(!$is_admin)
{
$query .= " WHERE type = 'staff' AND (staff LIKE '%\"".$user->ID."\"%' OR staff LIKE 'staff\"%' OR staff LIKE 'clientman%'";
if($is_staffman) $query .= " OR staff LIKE 'staffman%'";
if($is_accountant) $query .= " OR staff like 'accountant%'";
$query .= ")";
}
$query .= " ORDER BY updated DESC";
为什么?
1.See 通过 WHERE clause.There 过滤,您已经获得更少的记录(仅需要那些),获取所有记录并在 php 中过滤是没有意义的。
2.See 管理 PHP 中的代码很头疼,因为它变得复杂了。
3.Less no.of 行。
4.It 大部分时间由 SQL 管理,php 逻辑会使其变慢。
我接受了上面的答案,因为它是对我提出的问题的明确而明确的答案。但是,Stuart(在评论中)建议我尝试规范化我的结构,而不是使用 LIKES 等扫描序列化数组。这就是我所做的。
我没有以与 messages
table 相同的 table 序列化形式保存我的参与者数组,而是创建了一个名为 message_recipients
的新 table只有三列 (id,mid,user)
,其中 mid
指的是 messages
table 中的 id
列,user
存储个人用户 ID或角色名称。
所以最棘手的部分(实际上并不是那么棘手)是如何在用户更改给定消息的允许收件人时管理从 message_recipients
table 添加和删除行。 (在表单中,他们有两个多选下拉列表——一个用于员工,一个用于客户)。
下面是我管理 updated/changing 参与者部分的方式:
对于每个领域(员工和客户),我将两个数组传递给我的函数,一个是新参与者,一个是旧参与者。 (如果正在创建消息,那么旧的参与者数组就是空的。)
然后是函数(实际工作基本上就四行):
public function update_participants($mid = false, $new_staff = array(), $old_staff = array(), $new_clients = array(), $old_clients = array())
{
global $wpdb;
if(empty($mid)) return array();
$add = array_filter(array_unique(array_merge(array_diff($new_staff, $old_staff), array_diff($new_clients, $old_clients))));
$delete = array_filter(array_unique(array_merge(array_diff($old_staff, $new_staff), array_diff($old_clients, $new_clients))));
if(!empty($add)) $wpdb->query("INSERT INTO ".self::$participants." (mid,user) VALUES(".$mid.",\"".implode("\"),(".$mid.",\"", $add)."\")");
if(!empty($delete)) $wpdb->query("DELETE FROM ".self::$participants." WHERE mid = {$mid} AND user IN (\"".implode("\", \"", $delete)."\")");
return array('added'=>$add, 'deleted'=>$delete);
}
然后我 return 添加或删除的结果数组,所以我可以在我的电子邮件通知中使用它。
那么,既然我们已经规范化了,那么查询 table 以获取当前用户参与其中的所有消息的原始问题就变得更快更简单了:
$query = 'SELECT DISTINCT a.* FROM '.self::$messages.' a, '.self::$participants.' b';
if(!$is_admin)
{
$query .= ' WHERE (b.user = '.$user->ID;
if($is_client) $query .= ' OR b.user = "client"';
elseif($is_staff) $query .= ' OR b.user = "staff"';
else
{
if($is_clientman) $query .= ' OR b.user = "clientman"';
if($is_staffman) $query .= ' OR b.user = "staffman"';
if($is_accountant) $query .= ' OR b.user = "accountant"';
$query .= ' OR a.created_by = '.$user->ID;
}
$query .= ') AND b.mid = a.id';
}
$query .= ' ORDER BY a.updated DESC';
管理员可以得到所有信息,而其他人只会收到在参与者 table 中找到他们的用户 ID 或他们的用户角色的任何消息。 (有些角色有多个角色,因此是三重 if
语句,而不是 elseifs
。
我已经对不同用户的每一种可能配置进行了测试。奇迹般有效。
没有 LIKE,没有通配符,也没有 PHP 循环。
感谢大家的帮助。