如何减少获得此结果所需的查询数

时间:2010-09-29 16:03:08

标签: php mysql activerecord codeigniter

我正在CodeIgniter上编写一个应用程序来更好地整理我的电子书集。我差不多完成了,但是我意识到我的“浏览”页面运行了太多的查询 - 每本书有两个 - 以获取他们的信息。显然不是很理想,特别是因为我有大约1000本书可以投入到这个系统中。

我目前有一个模型函数可以获取所有书籍(最终将被修改以获取参数 - 这是下一步),另一个获取每个返回书籍的元信息。第二个功能是对每本书进行两次查询的功能 - 一个用于获取书表中的信息,另一个用于获取与书籍相关联的标签。以下是两个模型函数:

获取图书清单:

function get_books() {
    $this->db->select('isbn')->order_by('title');
    $query = $this->db->get('books');
    $result = $query->result();
    return $result;
}

获取图书元信息:

function get_book_info($isbn) {
    // Grab the book from Amazon
    $amazon = $this->amazon->get_amazon_item($isbn);

    // Get the book info
    $this->db->select('title, publisher, date, thumb, filename, pages');
    $query = $this->db->get_where('books', array('isbn' => $isbn));
    $bookResult = $query->row();

    // Get the book's tags
    $this->db->select('tag');
    $this->db->from('tags AS t');
    $this->db->join('books_tags AS bt', 'bt.tag_id = t.id', 'left');
    $this->db->where('bt.book_id', $isbn);
    $this->db->order_by('t.tag');
    $tagQuery = $this->db->get();
    foreach ($tagQuery->result() as $row) {
        $tagResult[] = $row->tag;
    }
    $tagResult = implode(', ', $tagResult);

    // Send data
    $data = array(
        'isbn' => $isbn,
        'thumb' => $bookResult->thumb,
        'title' => strip_slashes($bookResult->title),
        'file' => $bookResult->filename,
        'publisher' => strip_slashes($bookResult->publisher),
        'date' => date('F j, Y', strtotime($bookResult->date)),
        'pages' => $bookResult->pages,
        'tags' => $tagResult,
        'rating' => $amazon->Items->Item->CustomerReviews->AverageRating,
        'raters' => $amazon->Items->Item->CustomerReviews->TotalReviews
    );
    return $data;
}

我确定有一种方法可以编写一个或两个查询,将所有记录收集到我可以过滤的对象中,而不是每个都要写两个查询,但我不知道从哪里开始试图写出来。欢迎任何建议。

非常感谢, 马库斯

5 个答案:

答案 0 :(得分:2)

您想要做的是:

  1. 抓取所有图书及其标记的排序列表,
  2. 将它们标记为HTML,带有标签和评级。
  3. 将您的图书标记放在一起,拥有一个变量来跟踪您写下的最后一个ISBN,并且只有在ISBN更改时才会建立您的条目。所以,拉一个这样的集合:

    Book   | Tag
    ------ | ----------------
    Book A | Fiction
    Book A | Fantasy
    Book B | Mystery
    Book C | Science Fiction
    

    然后,每次在循环中书籍发生变化时,请写出“基本书籍信息”。显然,除了预订标记(例如 ISBN )之外,您还需要更多字段。

    如果您的亚马逊信息来自亚马逊,您可能无法选择重复调用他们的API(除非他们有“批处理”模式或其他东西,您可以提交一系列ISBN?)。

答案 1 :(得分:1)

在本主题的帮助下,以及在创建更好的查询的其他方面,我能够使用以下代码解决此问题:

function get_book_info() {

    /*
     * SELECT b.isbn, b.title, b.publisher, b.date, b.thumb, b.filename, b.pages, t.tag
     * FROM books AS b
     * INNER JOIN books_tags AS bt ON b.isbn = bt.book_id
     * INNER JOIN tags AS t ON bt.tag_id = t.id
     * ORDER BY b.title, t.tag
     */

    $this->db->select('b.isbn, b.title, b.publisher, b.date, b.thumb, b.filename, b.pages, t.tag');
    $this->db->from('books AS b');
    $this->db->join('books_tags AS bt', 'b.isbn = bt.book_id', 'inner');
    $this->db->join('tags AS t', 'bt.tag_id = t.id', 'inner');
    $this->db->order_by('b.title, t.tag');
    $query = $this->db->get();
    $result = $query->result();

    $counter = '';
    $record = $meta = $tags = array();
    $count = count($result);
    $i = 1;

    foreach ($result as $book) {
        // If this is not the last row
        if ($i < $count) {
            // If this is the first appearance of this book
            if ($counter != $book->isbn) {
                // If the meta array already exists
                if ($meta) {
                    // Add the combined tag string to the meta array
                    $meta['tags'] = implode(', ', $tags);
                    // Add the meta array
                    $record[] = $meta;
                    // Empty the tags array
                    $tags = array();
                }
                // Reset the counter
                $counter = $book->isbn;
                // Grab the book from Amazon
                $amazon = $this->amazon->get_amazon_item($book->isbn);
                // Collect the book information
                $meta = array(
                    'isbn' => $book->isbn,
                    'title' => strip_slashes($book->title),
                    'publisher' => strip_slashes($book->publisher),
                    'date' => date('F j, Y', strtotime($book->date)),
                    'thumb' => $book->thumb,
                    'file' => $book->filename,
                    'pages' => $book->pages,
                    'rating' => $amazon->Items->Item->CustomerReviews->AverageRating,
                    'raters' => $amazon->Items->Item->CustomerReviews->TotalReviews
                );
                // Add the tag to the tags array
                $tags[] = $book->tag;
            } else {
                // All we need is the tag
                $tags[] = $book->tag;
            }
        // If this is the last row
        } else {
            // If this is the first appearance of this book
            if ($counter != $book->isbn) {
                // Grab the book from Amazon
                $amazon = $this->amazon->get_amazon_item($book->isbn);
                // Collect the book information
                $meta = array(
                    'isbn' => $book->isbn,
                    'title' => strip_slashes($book->title),
                    'publisher' => strip_slashes($book->publisher),
                    'date' => date('F j, Y', strtotime($book->date)),
                    'thumb' => $book->thumb,
                    'file' => $book->filename,
                    'pages' => $book->pages,
                    'rating' => $amazon->Items->Item->CustomerReviews->AverageRating,
                    'raters' => $amazon->Items->Item->CustomerReviews->TotalReviews
                );
                // Add the tag to the tags array
                $tags[] = $book->tag;
                // Add the combined tag string to the meta array
                $meta['tags'] = implode(', ', $tags);
                // Add the meta array
                $record[] = $meta;
            } else {
                // All we need is the tag
                $tags[] = $book->tag;
                // Add the combined tag string to the meta array
                $meta['tags'] = implode(', ', $tags);
                // Add the meta array
                $record[] = $meta;
            }
        }
        $i++;
    }

    return $record;
}

可能有更好的方法来解决这个问题,但这就是我的逻辑看法。并且只有一个查询,总计。

答案 2 :(得分:0)

如果我说得对你:在表 books 中有关于这些书的所有数据: 这样做:

$this->db->select('*')->order_by('title');
$query = $this->db->get('books');
$result = $query->result();
return $result;

应该返回有关您图书的所有数据,您不需要再次循环来获取数据。

答案 3 :(得分:0)

我根本不熟悉CodeIgniter,但我认为你可以采用一些通用的做法。

  • 如果这是一个浏览页面 - 是不是有分页?对结果进行分页应大大减少每页加载时必须运行的查询数。
  • 您可以调用一个功能(例如,get_books_info())来检索所有标签&amp;您get_books()函数返回的所有图书的元信息。然后从get_book_info()引用该数组。您甚至可以从get_books_info()触发get_book_info() - 因此您只需要在需要数据时进行工作。我认为这种延迟加载。

答案 4 :(得分:0)

function get_book_info() {

    /*
     * SELECT b.isbn, b.title, b.publisher, b.date, b.thumb, b.filename, b.pages, t.tag
     * FROM books AS b
     * INNER JOIN books_tags AS bt ON b.isbn = bt.book_id
     * INNER JOIN tags AS t ON bt.tag_id = t.id
     * ORDER BY b.title, t.tag
     */

    $this->db->select('b.isbn, b.title, b.publisher, b.date, b.thumb, b.filename, b.pages, t.tag');
    $this->db->from('books AS b');
    $this->db->join('books_tags AS bt', 'b.isbn = bt.book_id', 'inner');
    $this->db->join('tags AS t', 'bt.tag_id = t.id', 'inner');
    $this->db->order_by('b.title, t.tag');
    $query = $this->db->get();
    $result = $query->result();

    $counter = '';
    $record = $meta = $tags = array();
    $count = count($result);
    $i = 1;

    foreach ($result as $book) {
        // If this is not the last row
        if ($i < $count) {
            // If this is the first appearance of this book
            if ($counter != $book->isbn) {
                // If the meta array already exists
                if ($meta) {
                    // Add the combined tag string to the meta array
                    $meta['tags'] = implode(', ', $tags);
                    // Add the meta array
                    $record[] = $meta;
                    // Empty the tags array
                    $tags = array();
                }
                // Reset the counter
                $counter = $book->isbn;
                // Grab the book from Amazon
                $amazon = $this->amazon->get_amazon_item($book->isbn);
                // Collect the book information
                $meta = array(
                    'isbn' => $book->isbn,
                    'title' => strip_slashes($book->title),
                    'publisher' => strip_slashes($book->publisher),
                    'date' => date('F j, Y', strtotime($book->date)),
                    'thumb' => $book->thumb,
                    'file' => $book->filename,
                    'pages' => $book->pages,
                    'rating' => $amazon->Items->Item->CustomerReviews->AverageRating,
                    'raters' => $amazon->Items->Item->CustomerReviews->TotalReviews
                );
                // Add the tag to the tags array
                $tags[] = $book->tag;
            } else {
                // All we need is the tag
                $tags[] = $book->tag;
            }
        // If this is the last row
        } else {
            // If this is the first appearance of this book
            if ($counter != $book->isbn) {
                // Grab the book from Amazon
                $amazon = $this->amazon->get_amazon_item($book->isbn);
                // Collect the book information
                $meta = array(
                    'isbn' => $book->isbn,
                    'title' => strip_slashes($book->title),
                    'publisher' => strip_slashes($book->publisher),
                    'date' => date('F j, Y', strtotime($book->date)),
                    'thumb' => $book->thumb,
                    'file' => $book->filename,
                    'pages' => $book->pages,
                    'rating' => $amazon->Items->Item->CustomerReviews->AverageRating,
                    'raters' => $amazon->Items->Item->CustomerReviews->TotalReviews
                );
                // Add the tag to the tags array
                $tags[] = $book->tag;
                // Add the combined tag string to the meta array
                $meta['tags'] = implode(', ', $tags);
                // Add the meta array
                $record[] = $meta;
            } else {
                // All we need is the tag
                $tags[] = $book->tag;
                // Add the combined tag string to the meta array
                $meta['tags'] = implode(', ', $tags);
                // Add the meta array
                $record[] = $meta;
            }
        }
        $i++;
    }

    return $record;
}