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) 甲骨文 11g R2
不幸的是,我们的应用程序具有每行安全“功能”。我们有一个看起来像这样的查询:
坏,慢:
SELECT someRow, someOtherRow
FROM bigTableA a
WHERE EXISTS (
SELECT 0 FROM bigTableA_securitymapping b
WHERE b.PrimaryKeyTableA = a.PrimaryKeyTableA AND
b.accesscode in (SELECT accesscode
FROM accesscodeView
WHERE user = :someUserID)
)
Run Code Online (Sandbox Code Playgroud)
上有一个唯一索引bigTableA_securitymapping(PrimaryKeyTableA,accesscode)。
将accesscodeView有可能返回多个accesscode给定用户,所以它必须是IN()不=。
问题是此查询忽略了唯一索引bigTableA_securitymapping并选择执行全表扫描。
如果我将 the 更改IN()为 an=那么它会UNIQUE SCAN在唯一索引上执行 abigTableA_securitymapping并且大约快 50 倍。
好,快但不可能:
SELECT someRow, someOtherRow
FROM bigTableA a
WHERE EXISTS (
SELECT 0 FROM bigTableA_securitymapping …Run Code Online (Sandbox Code Playgroud) 我在 SQL 方面遇到了一些麻烦:基本上,我试图获取一个结果集,其中包含向员工提出的所有问题的总和(按公司分组),并添加手动添加项目的“onetime_items”不同的表。
我目前有这个 SQL 语句(我使用的是 MySQL):
SELECT
CONCAT_WS(
', ', count(DISTINCT CONCAT(emailaddress, '_', e.id)),
(
SELECT GROUP_CONCAT(items SEPARATOR '; ') as OneTimeItems
FROM (
SELECT CONCAT_WS(
': ', oi.item_name, SUM(oi.item_amount)
) items
FROM onetime_item oi
WHERE oi.company_id = e.company_id
AND oi.date BETWEEN '2015-12-01'
AND LAST_DAY('2015-12-01')
GROUP BY oi.item_name
) resulta
)
) as AllItems,
e.id,
LEFT(e.firstname, 1) as voorletter,
e.lastname
FROM question q
LEFT JOIN employee e ON q.employee_id = e.id
WHERE 1=1
AND YEAR(created_at) = '2015'
AND MONTH(created_at) …Run Code Online (Sandbox Code Playgroud) 我正在尝试从历史表中为多个设备(唯一序列号)选择一系列数据,并想知道为什么以下查询的时间差异如此之大:
基本上我试图使用 IN 子句来指示我想要获取数据的项目。如果我对 IN 子句中的项目进行“硬编码”,则查询速度很快,如果我使用子查询或连接来选择项目,则性能很差。
此查询在 0.15 秒内完成并返回 7382 行。
SELECT `readings`.* FROM `readings`
WHERE
(SerialNumber IN ('091146000121', *snip 25*, '091146000556'))
AND (readings.time >= 1325404800)
AND (readings.time < 1326317400)
ORDER BY `time` ASC
Run Code Online (Sandbox Code Playgroud)
使用子查询重写以获取序列号的相同查询需要 30 多秒,并且似乎大部分时间都处于 Preparing 状态。它返回与第一个查询相同的数据。
SELECT `readings`.* FROM `readings`
WHERE
(SerialNumber IN (SELECT `boards`.`id` AS `SerialNumber` FROM `boards` WHERE (siteId = '1')))
AND (readings.time >= 1325404800)
AND (readings.time < 1326317400)
ORDER BY `time` ASC
Run Code Online (Sandbox Code Playgroud)
子查询返回与第一个查询中相同的值,但如前所述,这需要更长的时间来运行。 它们在功能上不是等效的吗?
这是两个查询的解释:
+----+-------------+----------+-------+---------------+---------+---------+------+------+-----------------------------+
| id | select_type | table | type …Run Code Online (Sandbox Code Playgroud) 过去 24 小时都在为某事挣扎。需要一些天才来发光。我正在尝试为驱动程序显示每周工作循环/日志,它将显示:
最后2点是我真正挣扎的地方。
我有以下表格:
drivers ('driver_id', 'driver_name')
vehicles ('vehicle_id', 'vehicle_make', 'vehicle_model')
jobs ('job_id', 'collection_address', 'collection_datetime', 'delivery_address', 'deliver_datetime', 'driver_id', 'vehicle_id')
Run Code Online (Sandbox Code Playgroud)
我附上了下面的输出屏幕:
例如,如果您查看 23/09/2016,司机 Keith 正在工作,但 Nick 有空。但是,如果我执行子查询,它会显示两个驱动程序,这不是正确的结果。我的 SQL 语句如下,如果有人可以提供帮助,我将不胜感激。
SELECT listofdays.job_date, j.job_id, IF( j.driver_id > 0 AND j.job_id > 0, (SELECT driver_name FROM t_drivers WHERE driver_id = j.driver_id LIMIT 1), '') as job_driver, IF( j.vehicle_id > 0, (SELECT vehicle_reg FROM t_vehicles WHERE vehicle_id = j.vehicle_id LIMIT 1), 'no') as job_vehicle, j.collection_town, j.collection_postcode, j.delivery_town, j.delivery_postcode, j.job_status
FROM …Run Code Online (Sandbox Code Playgroud) 我有以下查询(为简洁起见已删除),其目的是创建w8用于对结果进行排序的值:
SELECT elements.id, [ ... ],
(SELECT
COALESCE(craft_w8_a.weight, 0) + COALESCE(SUM(craft_w8_b.weight), 0)
FROM `craft_w8` `craft_w8_a`
LEFT JOIN `craft_w8` `craft_w8_b`
ON craft_w8_b.elementId
IN ( SELECT targetId FROM `craft_relations`
WHERE fieldId IN (15, 16)
AND sourceId = elements.id)
WHERE craft_w8_a.elementId = elements.id
) as w8
FROM `craft_elements` `elements`
[ ... ]
GROUP BY `elements`.`id`
ORDER BY `w8` DESC, `name` ASC LIMIT 100
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是第二个嵌套子查询(左连接中的那个)无法elements.id从初始选择中找到该列。
从我发现在 SQL 中搜索只传递一级深度的值,我一直无法找到合适的解决方法。
是否可以强制 SQL 传递比一级更深的值?或者有没有办法修改查询以不使用另一个子查询,但仍然得到相同的结果?
对不起,如果我做任何愚蠢的事情或遗漏了任何明显的东西,SQL 不是我的强项!
select(投影)的列字段中的子查询如何与主查询的结果配对?形式:
SELECT id,email,(SELECT name From Names WHERE Names.id=Users.id) as name
FROM Users
Run Code Online (Sandbox Code Playgroud)
子查询是从 , 的输出中每行执行一次SELECT id,email FROM Users,因此应该LIMIT 1在子查询上使用(因为子查询中只有 1 行可以与主查询中的一行配对),还是子查询运行一次,并且然后每个结果都与来自 的相应行配对SELECT id,email FROM Users,很像等效连接:SELECT id,email,name FROM Users JOIN Names ON Users.id=Names.id
我在做一些相当轻量级的数据按摩/清洁跑进其中使用相关子查询(可能是错误的)JOIN的一个版本跑了太大的问题很多比我相信这是正确的慢。我不问如何做查询(我相信现在我已经得到了正确的),但我想知道为什么慢版是如此缓慢。
问题
该域是一个相当简单的数据库,用于管理彩票辛迪加(记录会员付款、玩的游戏和获胜)。在转向新引擎 (SQLite) 时,我正在尝试清理数据并改进表的结构。
现有_Winnings表格记录了赢得的金额和日期以及“游戏类型”(可以玩多个游戏):
CREATE TABLE [_Winnings](
[ID] integer primary key not null,
[WinDate] date,
[Amount] integer,
[GameType] integer references _Games(ID)
);
CREATE INDEX [_WinningsIndex] on _Winnings(GameType) ;
Run Code Online (Sandbox Code Playgroud)
主要问题是没有链接(除了获胜日期)到实际玩的游戏。这些记录已经被迁移,现在保存在一个EventHistory表中:
CREATE TABLE [EventHistory](
[ID] integer primary key not null,
[EventType] integer references Events(ID),
[GameType] integer references Games(ID),
[EventDate] date
);
CREATE INDEX [EventHistoryEventIndex] on EventHistory(EventType) ;
CREATE INDEX [EventHistoryGameIndex] on EventHistory(GameType) ;
CREATE INDEX [EventHistoryDateIndex] on EventHistory(EventDate) ;
Run Code Online (Sandbox Code Playgroud)
三个表_Games, …
我正在尝试构建一个查询,该查询会生成一个由 SQL Server 生成的 JSON 对象。我发现我可以使用子查询用包含问题列表的 JSON 字符串填充字段(在本例中为问题字段)。
下面是查询:
SELECT
quizzes.id AS 'id',
quizzes.name AS 'name',
quizzes.description AS 'description',
quizzes.instructions AS 'instructions',
author.id AS 'author.id',
author.midas AS 'author.midas',
author.first_name AS 'author.first_name',
author.last_name AS 'author.last_name',
author.email AS 'author.email',
author.tel AS 'author.tel',
author.department_name AS 'author.department_name',
author.created_at AS 'author.created_at',
author.last_updated AS 'author.last_updated',
course.id AS 'course.id',
course.name AS 'course.name',
course.description AS 'course.description',
course.crn AS 'course.crn',
instructor.id AS 'course.instructor.id',
instructor.midas AS 'course.instructor.midas',
instructor.first_name AS 'course.instructor.first_name',
instructor.last_name AS 'course.instructor.last_name',
instructor.email AS 'course.instructor.email',
instructor.tel AS 'course.instructor.tel',
instructor.department_name …Run Code Online (Sandbox Code Playgroud) 我在我们的代码库中找到了这个查询:
DELETE FROM "Foo"
WHERE ("Foo"."Id", "Foo"."CreatedAt")
IN (SELECT "f"."Id", "f"."CreatedAt"
FROM "Foo" AS "f"
WHERE "f"."CreatedAt" <= CURRENT_TIMESTAMP);
Run Code Online (Sandbox Code Playgroud)
它删除当前时间之前创建的记录。
这给出了相同的结果:
DELETE FROM "Foo"
WHERE "Foo"."CreatedAt"
IN (SELECT "f"."CreatedAt"
FROM "Foo" AS "f"
WHERE "f"."CreatedAt" <= CURRENT_TIMESTAMP);
Run Code Online (Sandbox Code Playgroud)
我不知道为什么Foo.Id将 包含在WHERE子句中 - 也许是各种重构留下的垃圾(例如,它可能已用于批量删除ORDER BY "f"."Id" LIMIT 1000)。但因为这是一场PK,我不愿意删除它,因为也许它的存在是有原因的。
是否有理论/性能原因将其放在那里,或者这两个查询是否等效?
(这同时针对 postgres 和 sqlite。)
subquery ×10
mysql ×6
performance ×3
join ×2
query ×2
sqlite ×2
json ×1
optimization ×1
oracle ×1
postgresql ×1
select ×1
sql-server ×1