如果我说:
Table1 left join Table2
Run Code Online (Sandbox Code Playgroud)
和说一样吗?:
Table2 right join Table1
Run Code Online (Sandbox Code Playgroud)
换句话说,我是否应该期望从 2 个相同的查询中获得相同的结果,其中唯一改变的是首先写入哪个表以及是使用左连接还是右连接(遵循我上面描述的相同模式?)
ypercube 解决了这个问题。子查询是完全没有必要的,整个事情都可以使用普通连接。不过,MySQL 的优化器无法使用我的原始查询仍然很奇怪。有关问题和许多详细信息,请参见下文。在我的问题底部加上一个完整的解决方案。它基于 ypercube 的答案。
每个子查询都非常快,不到 1 秒。加入了 5-6 个子查询(一些LEFT,一些INNER),时间增加到 400 秒。
我用于测试的整体查询仅返回 441 行。
我尝试将每个子查询放在“CREATE TABLE”查询中。每一个都在不到 1 秒的时间内完成。然后我使用那些新创建的表重新执行外部查询,它的运行时间也远低于 1 秒。所以连接没有实际问题。我id为我创建的表添加了索引。所有表都在匹配id= 上连接id。
如何让 MySQL 高效地执行查询?我必须使用临时表吗?我已经编写了一堆 PHP 代码来将多个子查询连接放在一起,所以如果可能的话,我宁愿弄清楚如何使其工作。
我尝试使用“STRAIGHT_JOIN”关键字并删除外部ORDER BY. 这将查询时间减少到 90 秒。但我应该最多获得 1 秒。
我试过STRAIGHT_JOIN了ORDER BY,花了 235 秒。所以看起来外部ORDER BY是一个主要的性能问题。
编辑:
使用临时表进行测试。查询运行速度非常快。但是必须有一种方法可以让 mysql 使用 JOINS 快速完成它。
此外,慢查询日志显示:
Rows_examined: 484006914
Run Code Online (Sandbox Code Playgroud)
4.84 亿行看起来像笛卡尔积。为什么要检查这么多行?
查询具有以下结构:
SELECT t0.`id`, t1.`length`, t2.`height`, t3.`family`
FROM
`products` t0
INNER JOIN
( …Run Code Online (Sandbox Code Playgroud) 所以我想做一个左连接,让左表中的每一行都在右表中包含一行空值,即使存在匹配也是如此。
这种类型的连接有名称吗?
有没有比我下面的方法更好的方法(即避免联合)?
SELECT
T1.C1,
...
T1.CN
T2.C1,
...
T2.CM
FROM
Table1 T1
INNER JOIN Table2 T2
ON T1.Key1 = T2.Key1
UNION
SELECT
T1.C1,
...
T1.CN,
NULL, --NULL 1
...
NULL, --NULL M
FROM
Table1 T1
Run Code Online (Sandbox Code Playgroud)
(我也可以从左连接开始,然后联合一个选择,就像上面的第二个选择一样,过滤到仅具有匹配 ID 的表,但这仍然是复杂的方法)。
我想知道是否有类似的东西
SELECT
T1.C1,
...
T1.CN
T2.C1,
...
T2.CM
FROM
Table1 T1
INNER JOIN Table2 T2 INCLUDE_NULL_ROW_WITH_MATCH
ON T1.Key1 = T2.Key1
Run Code Online (Sandbox Code Playgroud)
如果相关的话,这是专门针对 SQL Server 2008 的。
+----+-----------+-----------+-------------+----------+
| id | value_id | parent_id | dropdown_id | name |
+----+-----------+-----------+-------------+----------+
| 7 | 14945 | 14944 | 57 |4000 |
| 8 | 14944 | 0 | 56 |bbb |
| 9 | 14943 | 14940 | 59 |comprable |
| 10 | 14942 | 14939 | 59 |comprable |
| 11 | 14940 | 14931 | 58 |3 |
| 12 | 14939 | 14930 | 58 |2 |
| 13 | 14931 | 14929 | …Run Code Online (Sandbox Code Playgroud) 我有 2 个表:tbl1、tbl2。
CREATE TABLE tbl1(time_1)
AS VALUES
( '2017-09-06 15:26:03'::timestamp ),
( '2017-09-06 15:26:02' ),
( '2017-09-06 15:28:01' ),
( '2017-09-06 15:40:00' );
CREATE TABLE tbl2(time_2)
AS VALUES
( '2017-09-06 15:29:01'::timestamp ),
( '2017-09-06 15:40:00' ),
( '2017-09-06 15:23:59' ),
( '2017-09-06 15:45:58' );
Run Code Online (Sandbox Code Playgroud)
我想加入表格,因此对于 tbl1 中的每一行都匹配 tbl2 中最接近的时间。输出是:
time_1 time_2
--------------------- --------------------
2017-09-06 15:26:03 2017-09-06 15:23:59
2017-09-06 15:26:02 2017-09-06 15:23:59
2017-09-06 15:28:01 2017-09-06 15:29:01
2017-09-06 15:40:00 2017-09-06 15:45:58
Run Code Online (Sandbox Code Playgroud)
我知道如何找到最近时间的单个值:
SELECT * from tbl1 where time_1=INPUT_TIME ORDER BY case …Run Code Online (Sandbox Code Playgroud) 我有一个关于这个查询计划的问题。
我们在测试环境中有一个表 Order_Details_Taxes,它有 11,225,799 行。该表有一个列 OrdTax_PLTax_LoadDtl_Key,它在每一行上都是 NULL。此测试环境的配置方式使此列始终为 NULL。此列上有一个索引。
我使用列的 NULL 值对该表运行了一些查询。NULL INNER JOIN 永远不会产生任何结果。
declare @Keys table (KeyValue decimal(15,0))
insert into @Keys (KeyValue) values (null)
select OrdTax_PLTax_LoadDtl_Key
from @Keys
inner join Order_Details_Taxes
on OrdTax_PLTax_LoadDtl_Key = KeyValue
select *
from @Keys
inner join Order_Details_Taxes
on OrdTax_PLTax_LoadDtl_Key = KeyValue
Run Code Online (Sandbox Code Playgroud)
这些是查询计划中的第一个查询。第一个select从亿行表开始并连接到@Keys。第二个select从@Keys 开始,但它对这个表进行聚集索引扫描。
我知道在大多数情况下临时@Tables 是有问题的,所以我将查询更改为使用临时 #Table:
if object_id ('tempdb..#Keys') is not null
drop table #Keys
create table #Keys (KeyValue decimal(15,0))
insert into #Keys (KeyValue) values (null)
select OrdTax_PLTax_LoadDtl_Key …Run Code Online (Sandbox Code Playgroud) 简介: 我有一个简单的数据库模式,但即使只有几十条记录,基本查询的性能也已经成为一个问题。
数据库:PostgreSQL 9.6
简化架构:
CREATE TABLE article (
id bigint PRIMARY KEY,
title text NOT NULL,
score int NOT NULL
);
CREATE TABLE tag (
id bigint PRIMARY KEY,
name text NOT NULL
);
CREATE TABLE article_tag (
article_id bigint NOT NULL REFERENCES article (id),
tag_id bigint NOT NULL REFERENCES tag (id),
PRIMARY KEY (article_id, tag_id)
);
CREATE INDEX ON article (score);
Run Code Online (Sandbox Code Playgroud)
生产数据信息:
所有表都是读/写的。写入量低,每几分钟左右只有一个新记录。
大概记录数:
每篇文章平均 5 个标签。
问题 …
我面临 SQL Server 生成非最佳执行计划的问题:嵌套循环连接并寻找维度表并对其执行 2M 读取。
排序操作估计是 100 行而不是 450 K 行,可能会影响计划选择:
NestedLoop:https ://www.brentozar.com/pastetheplan/ ? id = B110MZ2Pm或 NestedLoop 计划
这是在测试数据库中。我们有一个具有相同架构和几乎相同数据的附加数据库。
运行完全相同的查询(均来自 SSMS)使用哈希联接和维度表扫描(32K 读取)生成不同的计划:
HashJoin:https ://www.brentozar.com/pastetheplan/ ? id = r1Jm7b2D7或 哈希计划
我需要帮助来理解和解决问题。
我可以通过提示 Hash Joint 来解决这个问题,但是同一实例上的 2 个相似的 DB 生成不同的计划没有任何意义。
更新 #1:我发现估计的成本是不同的所以当 SQL Server 并行执行时,它会选择一个散列连接。
用单线程会嵌套循环。
更新 #2:在从同一个表中进行 SELECT 时发生了同样的问题。取决于列数(估计成本)。当我减少列数时,执行计划陷入嵌套循环并寻找维度表。
我养成了将连接条件与其他附加条件分开的习惯。不过我理解逻辑执行顺序是:
where如果我在子句中而不是子句中添加附加条件,是否会对性能产生不利影响join?或者这通常是在查询优化阶段得到简化和同等处理的部分?
以下是两个简单的示例查询,它们都返回相同的计划:
USE StackOverflow2010;
-- additional filters in where clause
SELECT TOP 500 p.id
FROM dbo.Posts p
INNER JOIN dbo.Votes v ON p.id = v.PostId
WHERE
v.VoteTypeId = 2
ORDER BY p.id
;
-- all criteria in on clause
SELECT TOP 500 p.id
FROM dbo.Posts p
INNER JOIN dbo.Votes v ON p.id = v.PostId AND v.VoteTypeId = 2
ORDER BY p.id
;
Run Code Online (Sandbox Code Playgroud)
我想补充一点,如果我编写较长的分析语句,通常跨越 100 行以上(格式化),我会尝试尽快减少结果集,通常使用派生表,并在到达连接之前添加一个额外的位置。
我正在尝试使用 CASE 表达式来选择每行应与哪个表连接。
假设我的游戏中有一个 item_instances 表,其中包含游戏世界中的所有项目,其中一些项目是 item_templates 表中通用项目的千篇一律的副本,而其他项目则以模板开始,然后当玩家使用它们时获得独特的属性。它们现在存储在 unique_items 表中。
因此,当我在 item_instances 表中找到某个项目的记录时,我想查找有关它的更多信息,并且需要从正确的表中提取该信息。
这是我一直在尝试但没有成功的事情:
SELECT item_table, item_id, *
FROM item_instances AS ii
JOIN
CASE ii.item_table
WHEN 0 THEN 'item_templates'
WHEN 1 THEN 'unique_items'
ELSE 'unique_items'
END
ON CASE = ii.item_id;
Run Code Online (Sandbox Code Playgroud)
如果有语法的快速修复,我很想听听。或者,如果这是您在概念上无法做到的事情 - 让每一行选择自己的连接 - 我很乐意获得更深入解释的链接。
过去,我通过执行两个 SELECT 来完成类似的操作,其中一个针对 item_templates 表,另一个针对 unique_items 表,并采用它们的 UNION。这感觉是一种更正确且更少浪费的方法。如果不是出于某种原因与 SQL 更深层次的架构有关,我想了解为什么。
join ×10
sql-server ×5
postgresql ×3
mysql ×2
performance ×2
case ×1
null ×1
optimization ×1
paging ×1
subquery ×1
time ×1