【问题标题】:Codeigniter database call efficiencyCodeigniter 数据库调用效率
【发布时间】:2011-11-11 17:30:23
【问题描述】:

这是一个效率/最佳实践问题。希望收到一些关于性能的反馈。非常感谢任何建议。

所以这里是我设置的一些背景知识。我正在使用 codeigniter,基本设置与任何其他产品关系非常相似。基本表是:品牌、产品、类别。除了这些表格之外,还需要安装表、营销材料和颜色。

我创建了一些关系表: 品牌_产品 产品展示_颜色 产品_图片 Products_Sheets

我还有一个 Categories_Relationships 表,其中包含与类别的所有关系。安装表等可以有自己的类别,但我不想为每种类型定义不同的类别关系表,因为我认为这不会非常可扩展。

在前端,我按品牌和类别进行排序。

我认为现在涵盖了效率部分的背景。我想我的问题主要与天气有关,最好使用连接或单独调用以返回每个项目的各个部分(颜色、图像等)

我目前编写的代码正在运行,并且排序很好,但我认为我可以提高性能,因为返回查询需要一些时间。现在它返回大约 45 件物品。这是我的第一个函数,它获取所有产品及其信息。

它首先选择所有产品并加入其品牌信息。然后循环遍历结果,我设置了基本信息,但是对于图像和安装类别,我使用的是返回每个受人尊敬的项目的函数。

public function all()
    {
        $q = $this->db
                    ->select('*')
                    ->from('Products')
                    ->join('Brands_Products', 'Brands_Products.product_id = Products.id')
                    ->join('Brands', 'Brands.id = Brands_Products.brand_id')
                    ->get();

        foreach($q->result() as $row)
        {
            // Set Regular Data
            $data['Id'] = $row->product_id;
            $data['Name'] = $row->product_name;
            $data['Description'] = $row->description;
            $data['Brand'] = $row->brand_name;
            $data['Category'] = $this->categories($row->product_id);
            $data['Product_Images'] = $this->product_images($row->product_id);
            $data['Product_Installs'] = $this->product_installs($row->product_id);
            $data['Slug'] = $row->slug;


            // Set new item in return object with created data
            $r[] = (object)$data;
        }


        return $r;
    }

这是用于获取各个部分的函数之一的示例。

private function product_installs($id)
    {
        // Select Install Images 
        $install_images = $this->db
                  ->select('*')
                  ->where('product_id', $id)
                  ->from('Products_Installs')
                  ->join('Files', 'Files.id = Products_Installs.file_id')
                  ->get();

        // Add categories to category object
        foreach($install_images->result() as $pImage)
        {
            $data[] = array(
                        'id' => $pImage->file_id, 
                        'src' => $pImage->src,
                        'title' => $pImage->title,
                        'alt' => $pImage->alt
                        );
        }

        // Make sure data exists
        if(!isset($data))
        {
            $data = array();
        }

        return $data;
    } 

所以真的只是在寻找关于什么是最有效、最佳实践的方法的建议。我非常感谢任何建议或信息。

【问题讨论】:

    标签: mysql performance codeigniter


    【解决方案1】:

    我认为你的方法是正确的。只有几个选项:1)首先加载您的产品列表,然后循环,并为每个产品行加载所需的数据。 2)首先在所有表上创建一个大连接,然后循环遍历(可能是大量的)笛卡尔积。第二个可能会变得很难解析。例如,如果您有产品 A 和产品 B,并且产品 A 有安装 1、安装 2、安装 3,而产品 B 有安装 1 和安装 2,那么您的结果是 产品 A 安装 1 产品 A 安装 2 产品 A 安装 3 产品 B 安装 1 产品 B 安装 2

    现在,将您的图像和类别添加到连接中,它可能会变得很大。

    我不确定您的表格的大小,但返回 45 行应该不会花很长时间。要确保(您可能已经这样做了)显而易见的事情是 product_id 在所有表以及您的brands_products 表和其他表中都有索引。否则,您将进行表扫描。

    下一个问题是您如何在屏幕上显示数据。所以你得到了所有的产品。当您获得产品列表时,您是否需要加载类别、图像、安装?如果您只是在屏幕上列出产品,您可能希望等待加载该数据,直到用户选择他们正在查看的产品。

    附带说明,您将数组转换为对象的任何原因

    $r[] = (object)$data;
    

    另外,在第二个函数中,你可以简单地添加

    $data = array();
    

    在 foreach 之前,而不是

    // Make sure data exists
    if(!isset($data))
    {
        $data = array();
    } 
    

    【讨论】:

    • 我猜你是对的,我在不需要的时候调用所有数据,不知道为什么我会忘记。我使用我目前的方法来完全避免您上面概述的内容,但我不确定这样做是否会导致很大的性能差异。我将它转换为一个对象,以便在前端我可以对所有内容使用 -> 语法。而不是 -> 有时和 array['key'] 其他时候。感谢您的建议,感谢您抽出宝贵时间。
    • 不客气。您可能需要考虑的其他一些改进:您的第一个函数中的 $q->result() 已经返回了一个对象数组。您将每个转换为数组,然后再转换回对象。 1)如果您坚持将列名从数据库更改为 php 所看到的,好的。 (意思是 id vs product_id,name vs product_name)。否则简单的重新运行 $q->result() 就完成了。 2)跳过创建数组并直接进入对象。 $data = 新的 stdClass(); $data->id = $row->product_id 等
    • 谢谢,我会改变它而不是来回转换。我要更改一些名称的原因是其他人正在处理一些前端,想让他们尽可能容易理解。
    【解决方案2】:

    你可以试试这个:

    1. 查询所有产品
    2. 从第 1 步获取所有产品 ID
    3. 查询具有步骤 2 中产品 ID 的所有安装映像,按产品 ID 排序
    4. 遍历步骤 1 中的产品,并添加步骤 3 中的结果

    这会将您从 46 个查询(针对 45 个产品)变为 2 个查询,无需任何额外的连接。

    您还可以使用 CodeIgniter 的 Query Caching 进一步提高性能,如果值得花时间编写代码以在数据更新时重置缓存。

    在可扩展性方面,在 PHP 中做更多的工作通常比在 MySQL 中做的更好。您可以使用负载平衡器和 Web 服务器轻松扩展 PHP。由于并发问题,扩展 MySQL 并不容易。

    【讨论】:

    • 我计划集成一些缓存,但还没有实现,我仍然想确保我在多次调用数据库时没有完全高效。感谢您的反馈,我会尝试一下,看看我能想出什么。
    • 效率低下是您设置它的方式无法扩展。对于 n 个产品,您总是有 n+1 个查询,而对 n 个产品有 2 个查询。即使没有缓存,2查询方式更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-19
    • 1970-01-01
    • 1970-01-01
    • 2013-04-05
    • 2012-04-18
    • 2012-04-27
    相关资源
    最近更新 更多