连接和包含生成的查询之间的差异

eivnm1vs  于 2021-07-24  发布在  Java
关注(0)|答案(3)|浏览(307)

我有以下查询 items 基于 document 订购日期。

items = ::Item.joins(:document).where(:documents => {:order_created_at => @start_date..@end_date, type: "Order"}).order(name: :asc)

以下是生成的sql:

SELECT  `items`.*
    FROM  `items`
    INNER JOIN  `documents`  ON `documents`.`id` = `items`.`document_id`
    WHERE  `documents`.`order_created_at`
           BETWEEN '2020-06-01 05:00:00'
               AND '2020-07-08 04:59:59'
      AND  `documents`.`type` = 'Order'
    ORDER BY  `items`.`name` ASC

这是一个基本的内部连接,所以很明显,我只得到与所选文档匹配的项。我想优化这个查询,因为我引用了 Document 模型,如 item.document.created_at . 为了做到这一点,我更换了 joinsincludes 在上面的查询中,有一个新的查询:

items = ::Item.includes(:document).where(:documents => {:order_created_at => @start_date..@end_date, type: "Order"}).order(name: :asc)

这运行得很好,但我不知道查询在逻辑上是否相同。如果您注意到的话,现在documents表和items表之间有一个左外连接。我不完全明白该怎么解释。为了优化的原因,除了includes方法之外,我正在尝试查询与join完全相同的项。结果查询如下:

SELECT "items"."id" AS t0_r0, "items"."name" AS t0_r1, "items"."description" AS t0_r2, 
"items"."shipping" AS t0_r3, "items"."sku" AS t0_r4, "items"."eta" AS t0_
r5, "items"."warranty" AS t0_r6, "items"."part_number" AS t0_r7, "items"."status" AS t0_r8, 
"items"."url_key" AS t0_r9, "items"."allow_rma" AS t0_r10, "items"."price" AS t0_r11,
"items"."meta_title" AS t0_r12, "items"."meta_keywords" AS t0_r13, 
"items"."meta_description" AS t0_r14, "items"."image" AS t0_r15, "items"."thumbnail" AS 
t0_r16, "items"."popularity" AS t0_r17, "items"."purchased_count" AS t0_r18, 
"items"."quantity" AS t0_r19, "items"."weight" AS t0_r20, "items"."created_at" AS t0_r21, 
"items"."updated_at" AS t0_r22,
"items"."document_id" AS t0_r23, "items"."product_id" AS t0_r24, "items"."total" AS t0_r25, 
"items"."warehouse_name" AS t0_r26, "items"."quantity_available" AS t0_r27, "items".
"quantity_to_return" AS t0_r28, "items"."reason_to_return" AS t0_r29, 
"items"."item_condition" AS t0_r30, "items"."resolution" AS t0_r31, "items"."brand" AS 
t0_r32, "items"."category" AS t0_r33, "items"."mod_name" AS t0_r34, "items"."product_type" 
AS t0_r35, "items"."search_variations" AS t0_r36, "items"."model_number" AS t0_r37, 
"items"."quantity_returned" AS t0_r38, "items"."line_number" AS t0_r39, 
"items"."external_id" AS t0_r40, "documents"."id" AS t1_r0, "documents"."status" AS t1_r1, 
"documents"."subtotal" AS t1_r2, "documents"."shipping" AS t1_r3, "documents"."handling" AS 
t1_r4, "documents"."grand_total" AS t1_r5, "documents"."total_paid" AS t1_r6, 
"documents"."total_refunded" AS t1_r7, "documents"."total_due" AS t1_r8, 
"documents"."order_prefix" AS t1_r9, "documents"."order_postfix" AS t1_r10, 
"documents"."shipping_method" AS t1_r11, "documents"."status_code" AS t1_r12, 
"documents"."created_at" AS t1_r13, "documents"."updated_at" AS t1_r14, 
"documents"."user_id" AS t1_r15, "documents"."downloaded_by_shipworks" AS t1_r16, 
"documents"."transaction_id" AS t1_r17, "documents"."settled" AS t1_r18, 
"documents"."voided" AS t1_r19, "documents"."voided_date" AS t1_r20, 
"documents"."voided_transaction_id" AS t1_r21, "documents"."tax" AS t1_r22, 
"documents"."payment_gateway" AS t1_r23, "documents"."admin_id" AS t1_r24, 
"documents"."purchase_order_number" AS t1_r25, "documents"."loaded_success_page" AS t1_r26, 
"documents"."discount_amount" AS t1_r27, "documents"."type" AS t1_r28, "documents"."token" 
AS t1_r29, "documents"."shipping_method_id" AS t1_r30, "documents"."document_id" AS t1_r31, 
"documents"."pay_without_credit_card" AS t1_r32, "documents"."order_created_at" AS t1_r33, 
"documents"."discount_id" AS t1_r34, "documents"."submitted_from_admin" AS t1_r35, 
"documents"."order_number" AS t1_r36, "documents"."marketplace" AS t1_r37, 
"documents"."amazon_prime" AS t1_r38, "documents"."discount_code" AS t1_r39, 
"documents"."discount_applied" AS t1_r40, "documents"."fulfillment_channel" AS t1_r41, 
"documents"."submitted_from_cron" AS t1_r42, "documents"."shipping_discount" AS t1_r43, 
"documents"."part_discount" AS t1_r44, "documents"."last_downloaded_by_fulfillment" AS 
t1_r45 FROM "items" LEFT OUTER JOIN "documents" ON "documents"."id" = "items"."document_id" 
WHERE "documents"."order_created_at" BETWEEN '2020-06-01 05:00:00' AND '2020-07-08 04:59:59' 
AND "documents"."type" = 'Order' ORDER BY "items"."name" ASC
yh2wf1be

yh2wf1be1#

值得注意的是 includes 以及 joins 有两个不同的用例。它们有时可能会生成类似的查询,但在其他情况下,它们会生成完全不同的查询。 joins 一方面产生 INNER JOIN 数据库查询。可用于查询联接表上有条件的记录。 joins 不加载相关记录。 includes 另一方面,用例是急于加载相关记录并避免n+1查询。rails可以使用数据库连接一次性加载记录及其关联的记录。或者它可能会启动两个查询来获取所有必需的记录。并不能保证它总是做一个数据库 JOIN .
也就是说:当你关心相关记录的使用时 includes . 当查询依赖于数据库时 INNER JOIN 然后使用 joins . 它们是不可互换的,尽管在某些情况下看起来像。

am46iovg

am46iovg2#

因为您还对文档的字段进行筛选 LEFT OUTER JOIN 是多余的。
它存在的原因是 includes 不会引起 item 即使它没有文档也被排除在外。
如果有 item 那没有一个 document 然而 where 会导致它被排除在外。
因为 order_created_atNULL 以及 NULL 不在开始日期和结束日期之间
因此,你实际上有一个 inner join 再一次。

brqmpdu1

brqmpdu13#

documents:  INDEX(type, order_created_at)  -- in that order
items:  INDEX(document_id)

伪“left”可能是生成查询的包的马虎。这对读者来说是混乱的,但对执行是无害的。mysql的优化器将看到这一点 documents 不是可选的(由于 WHERE 忽略 LEFT .

相关问题