我正在尝试优化 PostgreSQL 8.4 查询。在大大简化了原始查询之后,试图找出是什么让它选择了一个糟糕的查询计划,我发现在 EXPLAIN ANALYZE 下运行查询只需要 0.5 秒,而运行它通常需要 2.8 秒。那么很明显,EXPLAIN ANALYZE 显示给我的不是它通常所做的,所以它显示给我的都是无用的,不是吗?这里发生了什么,我如何看到它真正在做什么?
有没有什么合适的资源可以让我们完全理解hive生成的解释计划?我曾尝试在 wiki 中搜索它,但找不到完整的指南来理解它。这是 wiki,它简要解释了解释计划的工作原理。但我需要有关如何推断解释计划的更多信息。 https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Explain
我有点困惑,需要一些建议。我用PostgreSQL 11数据库。我有这么简单的sql语句:
SELECT DISTINCT "CITY", "AREA", "REGION"
FROM youtube
WHERE
"CITY" IS NOT NULL
AND
"AREA" IS NOT NULL
AND
"REGION" IS NOT NULL
Run Code Online (Sandbox Code Playgroud)
youtube我在 sql 语句中使用的表有 2500 万条记录。我认为这就是为什么查询需要 15-17 秒才能完成。对于我使用该查询的 Web 项目,它太长了。我正在尝试加快请求。
我为 youtube 表创建了这样的索引:
CREATE INDEX youtube_location_idx ON public.youtube USING btree ("CITY", "AREA", "REGION");
Run Code Online (Sandbox Code Playgroud)
在这一步之后,我再次运行查询,但需要相同的时间才能完成。似乎查询不使用索引。我如何知道查询中是否使用了任何索引?
我收到警告消息
查询在执行期间必须等待 xx 秒以获得 MemoryGrant
从 SQL 执行计划。我可以知道导致此警告消息出现的原因/可能性是什么吗?
是由于系统内存泄漏还是等待其他待处理的 SQL 查询完成?
我从 SQL 配置文件中提取了查询,该配置文件是从实体框架(Linq)生成并在 SSMS 2019 中运行的。
这是我的示例查询
Select table1.id
from table1
where table.id in (select table2.id
from table2
where table2.id in (select table3.id
from table3)
)
order by table1.id
limit 100
Run Code Online (Sandbox Code Playgroud)
在检查上述查询的优化器跟踪时。优化器跟踪成本
由于 DUPLICATE-WEEDOUT 成本较低,mysql 对上述查询采取了 DUPLICATE-WEEDOUT 策略。
join_optimization 部分似乎一切都很好。但最后,在检查了 join_execution 部分之后。DUPLICATE-WEEDOUT 通常会创建临时表。但是这里由于堆大小不足以容纳临时表,它继续创建磁盘临时表(converting_tmp_table_to_ondisk)。
由于磁盘临时表,我的查询执行变慢了。
那么这里发生了什么?
优化器跟踪不计算连接优化部分本身的磁盘表成本。如果计算磁盘表成本,它将高于第一次匹配。那么 final_semijoin_strategy 将是 FIRST-MATCH 策略,这样我的查询会更快。
MYSQL 有什么方法可以计算连接优化部分本身的磁盘表成本或针对此特定问题的任何其他解决方法吗?
MYSQ-5.7, INNODB
注意:这是一个非常动态的查询,其中多个条件将根据查询中的请求添加。所以我已经以所有可能的方式优化了查询。最后还是解决了这个磁盘表成本问题。请避免优化查询(如更改查询结构、强制优先匹配策略)。并且为了增加堆大小(我不太确定,在不同的论坛中很多人说它可能会在其他查询中带来不同的问题)
我有一个奇怪的问题,在设置nocheck外部约束并重新启用它之后,
我得到了与nocheckon 一起使用的同样过时的执行计划.
为什么SQL服务器会生成执行计划,就好像外部约束FKBtoA被禁用,即使再次使用以下语句添加检查?
alter table B check constraint FKBtoA
Run Code Online (Sandbox Code Playgroud)
[UPDATE1]
到目前为止,删除外部约束并读取它有效.
alter table B drop constraint FKBtoA
alter table B add constraint FKBtoA foreign key (AID) references A(ID)
Run Code Online (Sandbox Code Playgroud)
但对于真正的大桌子来说,这似乎是一种矫枉过正 - 有更好的方法吗?
[回答]
我不得不WITH CHECK在下面添加alter语句来获取旧的执行计划
alter table B WITH CHECK add constraint FKBtoA foreign key (AID) references A(ID)
Run Code Online (Sandbox Code Playgroud)
这是一个完整的SQL语句
create table A ( ID int identity primary key )
create table B (
ID int identity primary key,
AID int not null …Run Code Online (Sandbox Code Playgroud) 我有一张这样的桌子
CREATE TABLE IF NOT EXISTS `tbl_folder` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`owner_userid` int(11) NOT NULL,
`name` varchar(63) NOT NULL,
`description` text NOT NULL,
`visibility` tinyint(4) NOT NULL DEFAULT '2',
`num_items` int(11) NOT NULL DEFAULT '0',
`num_subscribers` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `owner_userid` (`owner_userid`),
KEY `vis_sub_item` (`visibility`,`num_subscribers`,`num_items`)
) ENGINE=InnoDB
Run Code Online (Sandbox Code Playgroud)
因为我有一个可见性索引,num_subscribers和num_items,我希望只需要查看前15行,而EXPLAIN说55856行.任何的想法?谢谢
EXPLAIN SELECT t.id, name, description, owner_userid, num_items, num_subscribers
FROM `tbl_folder` `t`
WHERE visibility =2
ORDER BY `t`.`num_subscribers` DESC , `t`.`num_items` DESC
LIMIT 15
id select_type …Run Code Online (Sandbox Code Playgroud) mysql indexing sql-order-by compound-index sql-execution-plan
我有一个非常简单的桌子,为人们存储标题("先生","太太"等).这是我正在做的简要版本(在这个例子中使用临时表,但结果是相同的):
create table #titles (
t_id tinyint not null identity(1, 1),
title varchar(20) not null,
constraint pk_titles primary key clustered (t_id),
constraint ux_titles unique nonclustered (title)
)
go
insert #titles values ('Mr')
insert #titles values ('Mrs')
insert #titles values ('Miss')
select * from #titles
drop table #titles
Run Code Online (Sandbox Code Playgroud)
请注意,表的主键是聚类的(显式,为了示例),并且标题列有一个非聚集唯一性约束.
以下是select操作的结果:
t_id title
---- --------------------
3 Miss
1 Mr
2 Mrs
Run Code Online (Sandbox Code Playgroud)
查看执行计划,SQL在群集主键上使用非聚集索引.我猜这解释了为什么结果按此顺序返回,但我不知道为什么它会这样做.
有任何想法吗?更重要的是,任何阻止这种行为的方法?我希望按照插入的顺序返回行.
谢谢!
sql-server clustered-index sql-execution-plan non-clustered-index
我运行以下mysql查询并查看第一个查询的类型为ALL.
mysql> EXPLAIN
SELECT one.language_id as filter_id,
one.language_name as filter_name,
two.count as count
FROM books_f9_languages one
INNER JOIN (SELECT language_id,
count(*) as count
FROM link_f9_books_lists
WHERE books_list_id IN (1691,1,2,3,4,6,7,8,9,10,11,12,13,14,17,18,19,20,21,22,23,24,25,26,28,29,30,31,32,33,34,35,36,37,43,44,47,51,54,57,58,59,68,71,76,77,86,88,93,94,99,120,125,126,127,133,146,147,148,257,260,261,262,263,264,266,267,268,269,270,271,272,275,276,286,767,768,769,771,772,774,777,779,783,785,786,790,792,799,808,811,813,814,815,819,825,828,829,847,850,852,853,855,856,857,858,862,863,866,869,873,875,882,891,900,907,917,925,930,935,1092,1531,1532,1533,1534,1535,1536,1537,1538,1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,1556,1557,1558,1560,1561,1563,1564,1565,1567,1568,1569,1570,1571,1572,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1586,1588,1589,1590,1591,1592,1595,1597,1599,1600,1601,1603,1604,1605,1606,1607,1608,1609,1610,1612,1613,1614,1615,1616,1617,1620,1621,1622,1623,1624,1625,1627,1628,1629,1630,1632,1636,1637,1638,1639,1640,1642,1643,1644,1645,1646,1648,1649,1651,1652,1653,1654,1659,1660,1662,1665,1675,1677,1679,1680,1689,1692,1693,1696,1698,1699,1702,1703,1705,1711,1713,1714,1716,1717,1719,1720,1726,1728,1729,1732,1734,1735,1736,1738,1743,1744,1753,1754,1755,1756,1759,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1797,1837,827) GROUP BY language_id) two
WHERE one.language_id = two.language_id
ORDER BY filter_name;
Run Code Online (Sandbox Code Playgroud)
这是输出,
+----+-------------+---------------------+--------+---------------+---------------+---------+-----------------+------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------------+--------+---------------+---------------+---------+-----------------+------+-----------------------------------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL …Run Code Online (Sandbox Code Playgroud) 我们有许多"搜索存储过程",它们采用多个可空参数来搜索不同表中的数据行.它们通常是这样构建的:
SELECT *
FROM Table1 T1
INNER JOIN Table2 T2
ON T2.something = T1.something
WHERE (@parameter1 IS NULL OR T1.Column1 = @parameter1)
AND (@parameter2 IS NULL OR T2.Column2 = @parameter2)
AND (@parameter3 IS NULL OR T1.Column3 LIKE '%' + @parameter3 + '%')
AND (@parameter4 IS NULL OR T2.Column4 LIKE '%' + @parameter4 + '%')
AND (@parameter5 IS NULL OR T1.Column5 = @parameter5)
Run Code Online (Sandbox Code Playgroud)
这可以持续多达30-40个参数,我们注意到即使只提供了parameter1,执行计划也会通过其他表的索引扫描,这会显着减慢查询速度(几秒钟).测试向我们表明,只保留WHERE语句的第一行使查询立即生效.
我已经读过,短路是不可能的,但有没有解决方法或构建可能更有效的查询的方法?
我们目前通过使用相同的SELECT/FROM/JOINS的不同版本但在WHERE子句中使用不同的参数集来解决这个问题,并且根据传递的参数,我们选择要经过的正确的select语句.这很长,很乱,很难维护.
sql ×4
sql-server ×4
mysql ×3
postgresql ×2
t-sql ×2
explain ×1
hadoop ×1
hive ×1
hiveql ×1
indexing ×1
innodb ×1
optimization ×1
sql-order-by ×1