- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我有一个 company
表和一个 industry
表,有一个多对多关系表链接这两个表,名为 company_industry
。 company
表目前大约有 750.000 行。
现在我需要一个查询来查找给定行业的所有唯一城市名称,其中至少有一家公司。所以基本上我必须找到与给定行业相关的所有公司,并为这些公司选择唯一的城市名称。
我可以编写很好地执行此操作的查询,但达不到我正在寻找的性能。之前我对性能有点怀疑,因为 city_name
列的类型是 VARCHAR
。不幸的是,我目前不可以自由地将数据库架构更改为更规范化的内容。
我做的第一件事是在 city_name
列上添加索引,然后我尝试了以下查询。
SELECT c.city_name AS city
FROM industry AS i
INNER JOIN company_industry AS ci ON (ci.industry_id = i.id)
INNER JOIN company AS c ON (c.id = ci.company_id)
WHERE i.id = 288
GROUP BY city;
上述查询平均需要大约两秒钟的时间来执行。将 GROUP BY
替换为 DISTINCT
时也是如此。下面是上述查询的执行计划。
HashAggregate (cost=56934.21..56961.61 rows=2740 width=9) (actual time=2421.364..2421.921 rows=1962 loops=1)
-> Hash Join (cost=38972.69..56902.50 rows=12687 width=9) (actual time=954.377..2411.194 rows=12401 loops=1)
Hash Cond: (ci.company_id = c.id)
-> Nested Loop (cost=0.28..13989.91 rows=12687 width=4) (actual time=0.041..203.442 rows=12401 loops=1)
-> Index Only Scan using industry_pkey on industry i (cost=0.28..8.29 rows=1 width=4) (actual time=0.015..0.018 rows=1 loops=1)
Index Cond: (id = 288)
Heap Fetches: 0
-> Seq Scan on company_industry ci (cost=0.00..13854.75 rows=12687 width=8) (actual time=0.020..199.087 rows=12401 loops=1)
Filter: (industry_id = 288)
Rows Removed by Filter: 806309
-> Hash (cost=26036.52..26036.52 rows=744152 width=13) (actual time=954.113..954.113 rows=744152 loops=1)
Buckets: 4096 Batches: 64 Memory Usage: 551kB
-> Seq Scan on company c (cost=0.00..26036.52 rows=744152 width=13) (actual time=0.008..554.662 rows=744152 loops=1)
Total runtime: 2422.185 ms
我尝试将查询更改为使用如下子查询,这使查询速度大约提高了一倍。
SELECT c.city_name
FROM company AS c
WHERE EXISTS(
SELECT 1
FROM company_industry
WHERE industry_id = 288 AND company_id = c.id
)
GROUP BY c.city_name;
以及这个查询的执行计划:
HashAggregate (cost=47108.71..47136.11 rows=2740 width=9) (actual time=1270.171..1270.798 rows=1962 loops=1)
-> Hash Semi Join (cost=14015.50..47076.98 rows=12690 width=9) (actual time=194.548..1251.785 rows=12401 loops=1)
Hash Cond: (c.id = company_industry.company_id)
-> Seq Scan on company c (cost=0.00..26036.52 rows=744152 width=13) (actual time=0.008..537.856 rows=744152 loops=1)
-> Hash (cost=13856.88..13856.88 rows=12690 width=4) (actual time=194.399..194.399 rows=12401 loops=1)
Buckets: 2048 Batches: 1 Memory Usage: 436kB
-> Seq Scan on company_industry (cost=0.00..13856.88 rows=12690 width=4) (actual time=0.012..187.449 rows=12401 loops=1)
Filter: (industry_id = 288)
Rows Removed by Filter: 806309
Total runtime: 1271.030 ms
更好,但希望你们能帮助我做得更好。
基本上,查询的昂贵部分似乎是查找唯一的城市名称(正如预期的那样),即使在列上有索引,性能也不够好。我在分析执行计划方面很生疏,但我把它们包括在内,这样你们就可以确切地看到发生了什么。
我怎样才能更快地检索这些数据?
我正在使用 Postgres 9.3.5,DDL 如下:
CREATE TABLE company (
id SERIAL PRIMARY KEY NOT NULL,
name VARCHAR(150) NOT NULL,
city_name VARCHAR(50),
);
CREATE TABLE company_industry (
company_id INT NOT NULL REFERENCES company (id) ON UPDATE CASCADE,
industry_id INT NOT NULL REFERENCES industry (id) ON UPDATE CASCADE,
PRIMARY KEY (company_id, industry_id)
);
CREATE TABLE industry (
id SERIAL PRIMARY KEY NOT NULL,
name VARCHAR(100) NOT NULL
);
CREATE INDEX company_city_name_index ON company (city_name);
最佳答案
两个查询计划中都有一个 Seq Scan on company_industry
,这实际上应该是(位图)索引扫描。 Seq Scan on company
也是如此。
似乎是缺少索引 的问题 - 或者您的数据库中存在某些不正确的地方。如果出现问题,请在继续之前进行备份。检查成本设置和统计是否有效:
如果设置良好,我会检查相关指标(详见下文)。也许 REINDEX
可以修复它:
REINDEX TABLE company;
REINDEX TABLE company_industry;
也许你需要做更多:
此外,您还可以简化查询:
SELECT c.city_name AS city
FROM company_industry ci
JOIN company c ON c.id = ci.company_id
WHERE ci.industry_id = 288
GROUP BY 1;
如果您的 PK 约束在 (company_id, industry_id)
上添加另一个(唯一的)索引 (industry_id, company_id)
(颠倒顺序!)。为什么?
Seq Scan on company
同样麻烦。 company(id)
似乎没有索引,但是您的 ER 图显示了 PK,所以这不可能?
最快的选择是在 (id, city_name)
上建立多列索引 - 如果(且仅当)您从中获得仅索引扫描。
因为您已经有了给定行业的 ID,所以根本不需要包含表 industry
表。
ON
子句中的表达式不需要括号。
这很不幸:
Unfortunately I do currently not have the liberty of being able to change the database schema to something more normalized.
您的简单模式对于几乎没有冗余且对可用缓存内存几乎没有压力的小表很有意义。但是城市名称在大表中可能是高度冗余的。 规范化会显着缩小表和索引的大小,这是影响性能的最重要因素。
具有冗余存储的非规范化形式有时可以加速目标查询,有时不能,这取决于。但它总是对其他一切产生不利影响。冗余存储会占用更多可用缓存,因此必须尽快清除其他数据。即使您在局部获得了一些东西,您也可能会失去整体。
在这种特殊情况下,为 city_id int
列获取不同的值也会便宜得多,因为 integer
值比(可能很长的)字符串更小且比较速度更快。 company
中 (id, city_id)
的多列索引将小于 (id, city_name)
的索引,并且处理速度更快。折叠许多重复项后再加入一个相对便宜。
如果您需要最佳性能,您可以随时添加一个 MATERIALIZED VIEW
用于特殊目的,使用预先计算的结果(易于聚合并使用 industry_id
的索引),但要避免在主表中使用大量冗余数据。
关于database - 使用 Postgres 在 varchar 列上使用 distinct/group by 进行慢速查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30275554/
我有一个包含电子邮件、IP、州、城市、时间戳、ID 列的表 我需要按州分组计算电子邮件和 IP 的不同位置 所以当我运行 MYSQL 查询时, select State, City ,count(di
我试过 select distinct ID from DB.TABLE; 它返回所有记录中的唯一 ID。 select distinct * from DB.TABLE; 它将通过比较所有列
我正在尝试在 Postgresql 中编写一个查询,该查询提取一组有序数据并按不同的字段对其进行过滤。我还需要从同一表行中提取其他几个字段,但需要将它们排除在不同的评估之外。示例: SELECT
我有一个使用以下语句创建的 Postgres 表。该表由另一个服务的数据转储填充。 CREATE TABLE data_table ( date date DEFAULT NULL,
我在一个名为 products 的表中有 4 列 id|p_name| p_img | 1 | Xs | xsmax.png | 2 | Xs | xr.png |
当它的状态仅为"is"时,我想从“num”中选择不同的值,而不是立即包括“否”? 表: +--------+-----+--------+ | id | num | status | +---
全部!今天我有一个棘手的问题要给你,我想使用 select DISTINCT 语句来选择一个需要不同的行,但也在同一个语句中(或者我尝试过的方式?)一个没有的行't/不能区分。我想要的结果是每个类名中
我有一个正在使用 Distinct() 的 linq 查询。如果我只是调用 Distinct() 而没有转换为列表,那么它不会返回不同的列表 - 它仍然包含重复项。 但是,如果我转换为 List 并然
说到性能,我应该使用 .ToList().Distinct() 还是 .Distinct().ToList() ? 两种扩展方法是否生成相同的 SQL 查询? 看起来第二种方法应该表现更好,但这是真的
如何在不支持 SQL Server 2008R2 的 SQL 实现中重写包含标准 IS DISTINCT FROM 和 IS NOT DISTINCT FROM 运算符的表达式? 最佳答案 IS DI
有一张 table (在 HIVE) 示例 - meanalytics.key2_master_ids 该表有 6 列(cmpgn_id、offr_id、exec_id、creatv_id、cmpl_
SELECT * FROM `amc_info` WHERE department =' ( SELECT DISTINCT department ) into outfile = 'Differe
如何在Elasticsearch中计算“不同的平均值”?我有一些这样的非规范化数据: { "record_id" : "100", "cost" : 42 } { "record_id" : "200
关注这个question我有... ID SKU PRODUCT ======================= 1 FOO-23 Orange 2 BAR
我有这个 mysql 查询: SELECT DISTINCT post.postId,hash,previewUrl,lastRetrieved FROM post INNER JOIN (tag a
http://sqlfiddle.com/#!2/37dd94/17 如果我执行 SELECT DISTINCT,我得到的结果与只执行 SELECT 的结果相同。 在查询结果中,您将看到两个包含 Di
我有一列包含空条目,例如此列中的可能值为 None, 1, 2, 3 当我使用 session.query(func.count(distinct(Entry.col))).scalar() 计算列中
这是否可能从表列中选择不同的行并计算单个查询中每个不同字段的重复行 $sql = "SELECT DISTINCT location and COUNT(DISTINCT location)
我在 MySQL 数据库中有一个包含 1100 万行的表。其中一列是个人身份证号码。人们在表中被多次列出,我想知道有多少个唯一的个人 ID 号码。然后创建一个包含这些唯一数字的表格。当我计算列中不同的
我刚刚注意到我的 Informix SQL 列(在同一个表中)的某些 上有些奇怪。当我执行此查询时 SELECT DISTINCT colName FROM myTable 例如,我得到 40 行。但
我是一名优秀的程序员,十分优秀!