我在20M行表上查询了以下内容:
ORDER BY (language_code = '%s') DESC, (language_code = '%s') DESC
%s
在运行时被替换为实际的语言代码(目的是对结果进行排序,以便用户语言中的那些首先排序,然后我们使用默认语言,最后是其他语言)。 / p>
我创建了以下索引:
CREATE INDEX 'index_on_language_code' ON 'my_table' (language_code)
然而,现在查询大约需要10秒,这太过分了,考虑到没有ORDER BY
子句,它只需要几毫秒。
有关更好索引的任何建议吗?
更新:
=> EXPLAIN for: SELECT "localized_skills".* FROM "localized_skills" ORDER BY (localized_skills.language_code = 'it') DESC, (localized_skills.language_code = 'en') DESC LIMIT 10
QUERY PLAN
Limit (cost=643126.40..643126.43 rows=10 width=42)
-> Sort (cost=643126.40..678294.56 rows=14067262 width=42)
Sort Key: (((language_code)::text = 'it'::text)), (((language_code)::text = 'en'::text))
-> Seq Scan on localized_skills (cost=0.00..339137.93 rows=14067262 width=42)
(4 rows)
更新2
在WHERE language_code = 'it' OR language_code = 'en'
(或等效解决方案)之前添加ORDER BY
并不会改善我的查询。事实上,我的数据目前,已经只是en或者它。这样可以防止在我用其他语言在数据库中添加更多行时增加时间,但查询时间不会少于10秒。
答案 0 :(得分:2)
您的索引在此ORDER BY
中无法使用。如果您有固定的字符串,您可以创建功能索引,例如language_code = 'it'
,但在这种情况下,我建议您使用WHERE language_code = 'it' OR language_code = 'en'
执行第一个查询命令这部分查询,而不是执行与所有其他语言的联合而不执行命令。你会有相同的结果,但我想得更快。
答案 1 :(得分:0)
SELECT "localized_skills".*
FROM "localized_skills"
ORDER BY (localized_skills.language_code = 'it') DESC,
(localized_skills.language_code = 'en') DESC
LIMIT 10
查询不包含WHERE
子句。这意味着将读取整个表,并且在没有LIMIT
子句的情况下,在结果集中返回。 LIMIT 10
在排序后的最后阶段发生。它无法阻止读取整个localized_skills
表。
由于ORDER BY
子句中的条件,RDBMS无法使用索引。它可能会创建一个临时表并将行存储在那里,可能会在运行中创建一个索引,以便能够以正确的顺序输出行。我不知道细节,我没有使用PostgreSQL
,但这就是MySQL
的作用,事实上,没有办法让它快速运行。
你真的需要现在使用查询,没有WHERE
子句吗?添加WHERE
子句会缩小已处理的行集。
一个简单的想法(无论是否添加WHERE
子句)是将查询拆分为两个查询,将条件移动到WHERE
子句中(可以与它们一起使用)索引可以显着减少已处理的行数。)
第一个查询选择最多 10行,其中包含所需的语言代码:
SELECT "localized_skills".*
FROM "localized_skills"
WHERE localized_skills.language_code IN ('it', 'en')
ORDER BY (localized_skills.language_code = 'it') DESC,
(localized_skills.language_code = 'en') DESC
LIMIT 10
如果第一个查询返回少于10行,那么您可以运行第二个查询来选择没有所需语言代码的剩余项目数:
SELECT "localized_skills".*
FROM "localized_skills"
WHERE localized_skills.language_code NOT IN ('it', 'en')
LIMIT 10 # Put a lower value here if needed
对于第二个查询,不再需要按language_code
排序行(两个条件都是FALSE
);这允许PostgreSQL
从表中选择第一行并阻止它读取整个表。
您甚至可以使用UNION
组合两个查询:
(
SELECT "localized_skills".*
FROM "localized_skills"
WHERE localized_skills.language_code IN ('it', 'en')
LIMIT 10
UNION
SELECT "localized_skills".*
FROM "localized_skills"
WHERE localized_skills.language_code NOT IN ('it', 'en')
LIMIT 10
)
ORDER BY (localized_skills.language_code = 'it') DESC,
(localized_skills.language_code = 'en') DESC
LIMIT 10
同样,我不知道PostgreSQL
,这是使用MySQL
实现结果的正确方法。我希望它可以帮助您使用PostgreSQL
语法和功能构建正确的查询。
ORDER BY
子句从第一个内部查询移动到UNION
,因为MySQL
不保留两个内部查询检索到的顺序或行。需要内部查询的LIMIT 10
子句以避免扫描整个表;外部LIMIT 10
子句在排序后只保留前10行。
答案 2 :(得分:0)
https://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html
显示
在某些情况下,MySQL无法使用索引来解析ORDER BY, 虽然它仍然使用索引来查找与WHERE匹配的行 条款。这些案例包括以下内容:
You use ORDER BY on nonconsecutive parts of a key: SELECT * FROM t1 WHERE key2=constant ORDER BY key_part2;
这就是你在做什么。
手册中的建议是
要提高ORDER BY速度,请检查是否可以使用MySQL 索引而不是额外的排序阶段。如果这不可能, 您可以尝试以下策略:
增加sort_buffer_size变量值。
增加read_rnd_buffer_size变量值。
每行使用较少的RAM,只需将列声明为保存存储在其中的值所需的大小。例如,CHAR(16)是 如果值永远不超过16个字符,则优于CHAR(200)。
将tmpdir系统变量更改为指向具有大量可用空间的专用文件系统。变量值可以列出 以循环方式使用的几条路径;你可以用它 功能将负载分散到多个目录中。路径应该是 在Unix和分号字符上用冒号字符(“:”)分隔 (“;”)在Windows,NetWare和OS / 2上。路径应该命名目录 在位于不同物理磁盘上的文件系统中,没有什么不同 同一磁盘上的分区。
或者可以通过
完成{query}
WHERE language_code = '%s'
UNION
{query}
WHERE language_code = '%s'
UNION
{query}
WHERE language_code NOT IN( '%1$s', '%2$s')