我将在Node.js(带有Express)和MySQL(mysql2包)中创建一个简单的Electron 商务数据库.

要获取单个产品,我需要从3个不同的表中获取数据:"Products"、"product_Images"(带有产品ID的外键)和"Review"(也带有产品ID的外键).

我的3个问题:

  const productQuery = `
    SELECT p.name, p.reference AS ref, p.price, p.brand, p.stock_qty, p.product_subcategory_id AS subcategoryId, p.product_promotion_id AS promotionId
    FROM products p
    WHERE id = ?
  `;
  const imagesQuery = `
    SELECT url
    FROM product_images
    WHERE product_id = ?
  `
  const reviewsQuery = `
  SELECT r.content AS reviewContent, r.rate AS reviewRate, r.created_at AS reviewDate, r.reviews_user_id AS reviewUserId
  FROM reviews r
  WHERE reviews_product_id = ?
  ORDER BY reviewDate DESC
  `;
  const [product] = await sql.query(productQuery, id);
  const [images] = await sql.query(imagesQuery, id);
  const [reviews] = await sql.query(reviewsQuery, id);
  return { product, images, reviews };

结果(我的种子中还没有图像,所以数组为空是正常的):

{
    "product": [
        {
            "name": "FAMILY CARE TRIPLE",
            "ref": "2c85da01",
            "price": "246.21",
            "brand": "Wordpedia",
            "stock_qty": "61",
            "subcategoryId": 21,
            "promotionId": null
        }
    ],
    "images": [],
    "reviews": [
        {
            "reviewContent": "Fusce posuere felis sed lacus. Morbi sem mauris, laoreet ut, rhoncus aliquet, pulvinar sed, nisl. Nunc rhoncus dui vel sem.",
            "reviewRate": 5,
            "reviewDate": "2023-03-04T11:12:13.000Z",
            "reviewUserId": 1
        },
        {
            "reviewContent": "Proin eu mi. Nulla ac enim. In tempor, turpis nec euismod scelerisque, quam turpis adipiscing lorem, vitae mattis nibh ligula nec sem.",
            "reviewRate": 4,
            "reviewDate": "2022-08-28T04:39:37.000Z",
            "reviewUserId": 1
        },
        {
            "reviewContent": "Praesent blandit. Nam nulla. Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede.",
            "reviewRate": 4,
            "reviewDate": "2022-08-19T17:05:23.000Z",
            "reviewUserId": 1
        },
        {
            "reviewContent": "Praesent id massa id nisl venenatis lacinia. Aenean sit amet justo. Morbi ut odio.",
            "reviewRate": 1,
            "reviewDate": "2022-08-19T16:05:44.000Z",
            "reviewUserId": 1
        },
        {
            "reviewContent": "Aenean lectus. Pellentesque eget nunc. Donec quis orci eget orci vehicula condimentum.",
            "reviewRate": 1,
            "reviewDate": "2022-06-18T00:50:21.000Z",
            "reviewUserId": 2
        }
    ]
}

结果是我想要的,但我不认为对数据库进行3次查询是优化的.

起初,我try 了这个查询(只是为了获取产品信息和相关 comments ,而不是图片).

`SELECT p.name, p.reference AS ref, p.price, p.brand, p.stock_qty, p.product_subcategory_id AS subcategoryId, p.product_promotion_id AS promotionId, r.content AS reviewContent, r.rate AS reviewRate, r.created_at AS reviewDate, r.reviews_user_id AS reviewUserId
FROM products p
JOIN reviews r
ON p.id = r.reviews_product_id
WHERE p.id = ?`

结果是:

[
    {
        "name": "FAMILY CARE TRIPLE",
        "ref": "2c85da01",
        "price": "246.21",
        "brand": "Wordpedia",
        "stock_qty": "61",
        "subcategoryId": 21,
        "promotionId": null,
        "reviewContent": "Proin eu mi. Nulla ac enim. In tempor, turpis nec euismod scelerisque, quam turpis adipiscing lorem, vitae mattis nibh ligula nec sem.",
        "reviewRate": 4,
        "reviewDate": "2022-08-28T04:39:37.000Z",
        "reviewUserId": 1
    },
    {
        "name": "FAMILY CARE TRIPLE",
        "ref": "2c85da01",
        "price": "246.21",
        "brand": "Wordpedia",
        "stock_qty": "61",
        "subcategoryId": 21,
        "promotionId": null,
        "reviewContent": "Aenean lectus. Pellentesque eget nunc. Donec quis orci eget orci vehicula condimentum.",
        "reviewRate": 1,
        "reviewDate": "2022-06-18T00:50:21.000Z",
        "reviewUserId": 2
    },
    {
        "name": "FAMILY CARE TRIPLE",
        "ref": "2c85da01",
        "price": "246.21",
        "brand": "Wordpedia",
        "stock_qty": "61",
        "subcategoryId": 21,
        "promotionId": null,
        "reviewContent": "Fusce posuere felis sed lacus. Morbi sem mauris, laoreet ut, rhoncus aliquet, pulvinar sed, nisl. Nunc rhoncus dui vel sem.",
        "reviewRate": 5,
        "reviewDate": "2023-03-04T11:12:13.000Z",
        "reviewUserId": 1
    },
    {
        "name": "FAMILY CARE TRIPLE",
        "ref": "2c85da01",
        "price": "246.21",
        "brand": "Wordpedia",
        "stock_qty": "61",
        "subcategoryId": 21,
        "promotionId": null,
        "reviewContent": "Praesent blandit. Nam nulla. Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede.",
        "reviewRate": 4,
        "reviewDate": "2022-08-19T17:05:23.000Z",
        "reviewUserId": 1
    },
    {
        "name": "FAMILY CARE TRIPLE",
        "ref": "2c85da01",
        "price": "246.21",
        "brand": "Wordpedia",
        "stock_qty": "61",
        "subcategoryId": 21,
        "promotionId": null,
        "reviewContent": "Praesent id massa id nisl venenatis lacinia. Aenean sit amet justo. Morbi ut odio.",
        "reviewRate": 1,
        "reviewDate": "2022-08-19T16:05:44.000Z",
        "reviewUserId": 1
    }
]

我的问题是,即使结果在技术上是正确的(我得到了我要求的所有数据),使用它也更困难(与我当前的代码相比),我猜它的效率不是很高,因为它有一些数据多次(每次不同的审查都会重复关于产品的相同数据).

所以我的问题是:有没有一种方法可以得到与我实际的结果一样的结果,但只需一次查询? 如果不是,我应该继续使用我的实际代码,还是应该使用我的第一个代码?

推荐答案

我将继续使用三个问题.如果您可以用一个查询就能做到这一点,那么这个查询将非常复杂,并且很难维护.此外,您还必须在获取结果后编写大量代码,以将结果分离到您想要的 struct 中.

在上面的 comments 中,Shadow指的是可以生成JSON struct 化结果的SQL查询.这将类似于以下内容(例如,目的不是作为 case 的解决方案):

SELECT JSON_OBJECT(
  'product', p.products,
  'images', i.images,
  'reviews', r.reviews,
) AS _result
FROM (
  SELECT JSON_ARRAYAGG(
    JSON_OBJECT(
      'name', name,
      'ref', reference,
      'price', price,
      'brand', brand,
      'stock_qty', stock_qty,
      'subcategoryId', product_subcategory_id,
      'promotionId', 'product_promotion_id
    )
  ) AS products
  FROM products
  WHERE id = ?
) AS p
CROSS JOIN (
  ...similar for product_images table...
) AS i
CROSS JOIN (
  ...similar for reviews table...
) AS r;

这更难编写,也更难向其他开发人员解释,而且如果将来需要添加新元素,也很难添加.

有时,更简单的方法更适合您的代码的生命周期.

这让我想起了这句来自Brian Kernighan年的classic 名言:

每个人都知道,调试比一开始编写程序要难一倍.所以,如果你在写它的时候尽可能地聪明,你将如何调试它呢?

另一条 comments :你说你猜到有三个查询效率不高.但是,这种模糊的猜测并不足以使其成为一个更复杂的查询.您应该有一个原始实现不够好的更具体的原因,您可以通过一些性能测量来支持这一点.

Mysql相关问答推荐

括号在SQL查询中的作用?

SQL Store Procedure Throwing [42000][1064]您在EXECUTE stat USING声明上的SQL语法中有错误

MySQL多次联接同一个表使计数变得奇怪

使用复合主键更新后的MySQL触发器失败

mysql 获取每个单词的第一个字母

获取连续11天未考勤的员工

实体内约束的唯一增量 ID 生成

如何本地化 MySQL 表中的实体?

如何根据 R 中的价格范围将数据从一列复制到新列?

在 Spring Data jpa 中的 @Query 中无法识别本机查询

即使使用索引,MySQL 计数和按查询分组也很慢

Django中的MYSQL查询等效

从 2 个不同的表中获取数据并将它们加入 sql

使用 ON DUPLICATE KEY 将列增加一定数量 MySQL NodeJS

在 MySQL 的存储过程中调用存储过程

在 WHERE 子句中使用 CASE

在 Android 上运行 AMP (apache mysql php)

MySQL:按字段排序,将空单元格放在末尾

如何存储重复日期牢记夏令时

将 JavaScript 到日期对象转换为 MySQL 日期格式 (YYYY-MM-DD)