【问题标题】:Can I use a php function to perform the equivalent of a mySQL left join?我可以使用 php 函数来执行相当于 mySQL 左连接的操作吗?
【发布时间】:2011-09-27 16:20:51
【问题描述】:

我遇到的问题是使用下面的当前函数加载时间太长。正在连接的两个表各包含数千行。保存表连接的特定函数是下面模型部分中的&getFields() 函数。

我在想我可能有一个函数,它最初检查请求是编辑还是添加新请求,然后处理仅在编辑查询上分离表连接(不知道如何完成此操作)。


从页面初始页面调用 - 使用带有 post 方法的 html 表单

如果(计数($this->fields)){ for($i=0;$ifields);$i++){ $field =& $this->fields[$i]; $se = $field->section; $ti = $field->标题; $ft = $字段->类型; $na = $字段->名称; $fva = $field->field_value; $nu = $field->单位; 开关($se){ 案例“标题”: 回声'输入类型=“废话...


控制器将流量导向模型

函数 __construct() { 父::__construct(); $this->registerTask('add','edit'); JRequest::setVar('view','cpanel'); } 功能编辑(){ JRequest::setVar('layout','form'); 父::显示(); } 函数保存(){ $model = $this->getModel('cpanel'); $msg = $model->store(); $链接 = ; $this->setRedirect($link, $msg); }


拥有实际功能的模型

函数 __construct() { 父::__construct(); 全球$大型机; $array = JRequest::getVar('cid', 0, '', 'array'); $this->setId((int)$array[0]); } 函数 setId($id) { // 设置id并擦除数据 $this->_id = $id; $this->_data = null; } 函数 &getItem() { 如果(空($this->_data)){ $query = ' SELECT * FROM #__directory_entry WHERE id = '.$this->_id; $this->_db->setQuery( $query ); $this->_data = $this->_db->loadObject(); } if(!$this->_data) { $session =& JFactory::getSession(); $post = $session->get('post'); $this->_data->id = 0; $this->_data->title = isset($post['title'])?$post['title']:null; } 返回 $this->_data; } 函数 &getFields() { $query = 'select f.*, ef.field_value from #__directory_field as f left join
#__directory_enf as ef on (f.id = ef.field_id and ef.entry_id = '.$this->_id.')其中
f.published = 1 order by f.ordering asc';
$this->_db->setQuery( $query ); $fields = $this->_db->loadObjectList(); $session =& JFactory::getSession(); if($session->has('post') 和 !$this->_id) { $post = $session->get('post'); for($i=0;$ifield_value = isset($post['field_'.$fields[$i]->name])?$post['field_'.$fields[$i]->name]:null ; } 返回$字段; } 函数存储(){ // 检查请求伪造 JRequest::checkToken() 或 jexit( JText::_('Invalid Token') ); $post = JRequest::get('post'); $session =& JFactory::getSession(); $session->set('post', $post); if($post["title"] == "") return JText::_('请输入标题'); $query = 'select * from #__directory_field where published = 1'; $this->_db->setQuery( $query ); $fields = $this->_db->loadObjectList(); for($i=0;$irequired 和 $post['field_'.$fields[$i]->name] == "") return JText::_($fields[$i]->title . '是必填字段,不能留空。'); } if(!$post["id"]) { $date =& JFactory::getDate(); $post['create_date'] = $date->toMySQL(); $post['排序'] = 1; $query = '从#__directory_entry order by ordering desc limit 1中选择排序'; $this->_db->setQuery( $query ); $post['ordering'] += $this->_db->loadResult(); $post['已发布'] = 1; } $me =& JFactory::getUser(); JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_joomd'.DS.'tables'); $row =& JTable::getInstance('entry', 'Table'); if (!$row->bind($post)) return JText::_('对不起,发生了一些错误。'); if (!$row->store()) 返回 $this->_db->getErrorMsg(); if(!$post['id']) { $post['id'] = $this->_db->insertid(); JRequest::setVar('id', $post['id']); $msg = JText::_('条目添加成功!'); $query = '插入#__directory_enu (entry_id, user_id) 值('.$post['id'].', '.$me->id.')'; $this->_db->setQuery( $query ); $this->_db->query(); } 别的 $msg = JText::_('条目更新成功!'); $max_size = 10000000; jimport('joomla.filesystem.file'); $时间=时间(); for($i=0;$itype == "图像") $allowed = array('.jpg', '.jpeg', '.gif', '.png'); elseif($field->type == "文件") $allowed = array('.doc', '.docx', '.pdf', '.txt', '.exl', '.xls', '.xlsx', '.jpg', '.jpeg', '.gif', '.png', '.zip'); $标志=真; $query = 'select count(*) from #__directory_enf where entry_id = '。 $post["id"] 。和 field_id = ' 。 $field->id; $this->_db->setQuery( $query ); $count = $this->_db->loadResult(); if($field->type == "image" 或 $field->type == "file") { $image = JRequest::getVar("field_".$field->name, null, 'FILES', 'array'); $image_name = str_replace(' ', '', JFile::makeSafe($image['name'])); $image_tmp = $image["tmp_name"]; 如果($图像名称“”){ $ext = strrchr($image_name, '.'); if(!in_array($ext, $allowed)) return sprintf(JText::_('%s 的文件类型不允许。'), $field->title); 如果(文件大小($image_tmp)> $max_size) return sprintf(JText::_('%s 的文件大小超过了最大文件大小。'), $field->title); if(move_uploaded_file($image_tmp, JPATH_SITE.'/files/'.$time.$image_name)) $post["field_".$field->name] = $time.$image_name; 别的 return sprintf(JText::_('抱歉,无法上传 %s 的文件。'), $field->title); } 别的 $标志=假; } 如果($标志){ 如果($计数){ $query = '从 #__directory_enf 中选择 id,其中 entry_id = '.$post["id"].'和 field_id = ' 。 $field->id; $this->_db->setQuery( $query ); $field_id = $this->_db->loadResult(); $update = 新的 stdClass(); $update->id = $field_id; $update->field_value = $post["field_".$field->name]; $this->_db->updateObject('#__directory_enf', $update, 'id'); } 别的 { $插入 = 新标准类(); $插入->id = null; $插入->field_id = $field->id; $insert->entry_id = $post["id"]; $insert->field_value = $post["field_".$field->name]; $this->_db->insertObject('#__directory_enf', $insert, 'id'); } } } $session->clear('post'); 返回$味精; }

【问题讨论】:

  • 也许您可以尝试将问题缩小到比“这里有几百行代码,修复它”更具体的问题。如果您有正确的索引,在 MySQL 中连接数百万行的表会很快 - 数千行不应该是任何麻烦。
  • 您是否在 ON 子句中的键上使用索引?
  • PHP 或任何其他应用程序语言永远无法像 SQL 一样进行扩展(1K、10K、100K 等记录)。
  • 放置大量代码的原因是为了提供尽可能多的信息。主要问题在于 &getFields()。根据我的研究,处理速度慢的可能原因是表连接。一位消息人士解释说,连接 2 个表不仅会使处理压力增加一倍,而且会大大增加。
  • 除了索引您要连接的字段之外,我还建议您只选择您需要的字段。尽量避免 f.*

标签: php mysql sql


【解决方案1】:

Left Join 是最快的方法,但是您编写查询的方式会非常慢。

SELECT f.*, ef.field_value
   FROM #__directory_field AS f
   LEFT JOIN #__directory_enf AS ef ON (f.id = ef.field_id AND ef.entry_id = $this->_id)
   WHERE f.published = 1
   ORDER BY f.ordering ASC

您的 ON 子句是主要问题。以这种方式编写,您将跟踪每条记录,并且没有很好地利用索引。您将需要颠倒您的表顺序,并将 id 匹配放在 where 子句中。像这样的。

SELECT ef.field_value, f.*
   FROM #__directory_enf AS ef
   LEFT JOIN #__directory_field AS f ON f.id = ef.field_id
   WHERE f.published = 1 AND ef.entry_id = $this->_id
   ORDER BY f.ordering ASC

然后,您需要确保您的数据库在 f.id 和 ef.entry_id 字段上都有索引。这应该会使您的查询速度提高很多倍。

【讨论】:

    猜你喜欢
    • 2013-05-18
    • 2016-03-11
    • 1970-01-01
    • 1970-01-01
    • 2012-06-23
    • 2013-06-22
    • 1970-01-01
    • 1970-01-01
    • 2021-08-22
    相关资源
    最近更新 更多