使用多个 IN 优化查询
Optimizing a query with multiple IN
我有这样的查询:
SELECT * FROM table
WHERE department='param1' AND type='param2' AND product='param3'
AND product_code IN (10-30 alphanumerics) AND unit_code IN (10+ numerics)
AND first_name || last_name IN (10-20 names)
AND sale_id LIKE ANY(list of regex string)
运行时间太长,所以我被要求优化它。
参数列表因不同用户的代码列而异。
每个用户提供他们的代码列表,然后循环访问产品。
product 曾经也是一个 IN 子句列表,但它被拆分了。
我尝试过的东西
通过在(部门、类型和产品)上添加索引,我获得了 4 倍的改进。
目前的运行时间是product有的值只需要2-3秒,有的需要30s。
尝试创建 first_name 的预连接列 || last_name,但运行时改进太小,不值得。
有什么方法可以提高其他子句的性能,例如“IN”子句或 LIKE ANY 子句?
根据我的经验,使用 VALUES 子句的 JOIN 替换大型 IN 列表通常会提高性能。
所以代替:
SELECT *
FROM table
WHERE department='param1'
AND type='param2'
AND product='param3'
AND product_code IN (10-30 alphanumerics)
使用:
SELECT *
FROM table t
JOIN ( values (1),(2),(3) ) as x(code) on x.code = t.product_code
WHERE department='param1'
AND type='param2'
AND product='param3'
但是您必须确保 values ()
列表中没有任何重复项
连接也是错误的,因为连接后的值与单独比较每个值不同,例如('alexander', 'son') would be treated identical to
('alex', 'anderson')`
你应该使用:
and (first_name, last_name) in ( ('fname1', 'lname1'), ('fname2', 'lname2'))
这个也可以写成join
SELECT *
FROM table t
JOIN ( values (1),(2),(3) ) as x(code) on x.code = t.product_code
JOIN (
values ('fname1', 'lname1'), ('fname2', 'lname2')
) as n(fname, lname) on (n.fname, n.lname) = (t.first_name, t.last_name)
WHERE department='param1'
AND type='param2'
AND product='param3'
您通常不需要做任何特殊的事情来使索引能够与多个 IN 列表一起使用,除了保持 table 良好的清理和分析。 (department, type, product, product_code, unit_code, (first_name || last_name))
上的 btree 索引应该运行良好。如果没有,请为其显示 EXPLAIN (ANALYZE, BUFFERS)
,最好打开 track_io_timing
。如果您的每个条件的选择性不是相互独立的,那可能会导致规划问题。
我有这样的查询:
SELECT * FROM table
WHERE department='param1' AND type='param2' AND product='param3'
AND product_code IN (10-30 alphanumerics) AND unit_code IN (10+ numerics)
AND first_name || last_name IN (10-20 names)
AND sale_id LIKE ANY(list of regex string)
运行时间太长,所以我被要求优化它。
参数列表因不同用户的代码列而异。 每个用户提供他们的代码列表,然后循环访问产品。 product 曾经也是一个 IN 子句列表,但它被拆分了。
我尝试过的东西
通过在(部门、类型和产品)上添加索引,我获得了 4 倍的改进。 目前的运行时间是product有的值只需要2-3秒,有的需要30s。
尝试创建 first_name 的预连接列 || last_name,但运行时改进太小,不值得。
有什么方法可以提高其他子句的性能,例如“IN”子句或 LIKE ANY 子句?
根据我的经验,使用 VALUES 子句的 JOIN 替换大型 IN 列表通常会提高性能。
所以代替:
SELECT *
FROM table
WHERE department='param1'
AND type='param2'
AND product='param3'
AND product_code IN (10-30 alphanumerics)
使用:
SELECT *
FROM table t
JOIN ( values (1),(2),(3) ) as x(code) on x.code = t.product_code
WHERE department='param1'
AND type='param2'
AND product='param3'
但是您必须确保 values ()
列表中没有任何重复项
连接也是错误的,因为连接后的值与单独比较每个值不同,例如('alexander', 'son') would be treated identical to
('alex', 'anderson')`
你应该使用:
and (first_name, last_name) in ( ('fname1', 'lname1'), ('fname2', 'lname2'))
这个也可以写成join
SELECT *
FROM table t
JOIN ( values (1),(2),(3) ) as x(code) on x.code = t.product_code
JOIN (
values ('fname1', 'lname1'), ('fname2', 'lname2')
) as n(fname, lname) on (n.fname, n.lname) = (t.first_name, t.last_name)
WHERE department='param1'
AND type='param2'
AND product='param3'
您通常不需要做任何特殊的事情来使索引能够与多个 IN 列表一起使用,除了保持 table 良好的清理和分析。 (department, type, product, product_code, unit_code, (first_name || last_name))
上的 btree 索引应该运行良好。如果没有,请为其显示 EXPLAIN (ANALYZE, BUFFERS)
,最好打开 track_io_timing
。如果您的每个条件的选择性不是相互独立的,那可能会导致规划问题。