如何使用数千个WHERE子句优化SQL查询

时间:2010-04-19 15:29:35

标签: sql database oracle

我对一个非常庞大的大型数据库进行了一系列查询,而且我在WHERE子句中有数十万个OR。优化此类SQL查询的最佳和最简单的方法是什么?我发现了一些关于创建临时表和使用连接的文章,但我不确定。我是严肃的SQL新手,并且已经将结果剪切并粘贴到下一个。

SELECT doc_id, language, author, title FROM doc_text WHERE language='fr' OR language='es'
SELECT doc_id, ref_id FROM doc_ref WHERE doc_id=1234567 OR doc_id=1234570 OR doc_id=1234572 OR doc_id=1234596 OR OR OR ...
SELECT ref_id, location_id FROM ref_master WHERE ref_id=098765 OR ref_id=987654 OR ref_id=876543 OR OR OR ...
SELECT location_id, location_display_name FROM location
SELECT doc_id, index_code, FROM doc_index WHERE doc_id=1234567 OR doc_id=1234570 OR doc_id=1234572 OR doc_id=1234596 OR OR OR x100,000

这些未经优化的查询每次可能需要24小时。欢呼声。

4 个答案:

答案 0 :(得分:7)

我想我刚回答了自己的问题...... NESTED TABLES!

SELECT doc_text.doc_id, doc_text.language, doc_text.author, doc_text.title, doc_ref.ref_id, ref_master.location_id, location.location_display_name, doc_index.doc_id, doc_index.display_heading
FROM DOC_TEXT, DOC_REF, REF_MASTER, LOCATION, DOC_INDEX
WHERE
    doc_text.language='fr' OR doc_text.language='es'
AND
    doc_text.doc_id=doc_ref.doc_id
AND
    doc_ref.doc_id=ref_master.ref_id
AND
    ref_master.location_id=location.location_id
AND
    doc_text.doc_id=doc_index.doc_id

答案 1 :(得分:5)

完成这项工作的最简单方法是:

  • 在要过滤的列(languageref_iddoc_id等)上制作索引,至少仔细检查它们的存在。如果它们是表的主索引,则使它们成为聚类。
  • 创建包含条件的辅助表(通过INSERT / DELETE语句添加/删除条件),也将它们编入索引。
  • 而不是1000“OR”组件,进行INNER JOIN:

因此...

SELECT doc_id, language, author, title 
  FROM doc_text
 WHERE language='fr' OR language='es'

变为

INSERT language_search (language) VALUES ('fr')
INSERT language_search (language) VALUES ('es')
/* and 50 more */

SELECT dt.doc_id, dt.language, dt.author, dt.title 
  FROM doc_text dt
       INNER JOIN language_search ls ON dt.language = ls.language

答案 2 :(得分:3)

您可以使用in关键字代替在同一字段中设置很多条件:

SELECT doc_id, ref_id FROM doc_ref WHERE doc_id in (1234567, 1234570, 1234572, 1234596, ...)

这会缩短查询时间,但不确定性能会有多大差异。您应该确保在相关字段上有索引,这通常会对性能产生巨大影响。

修改

但是,似乎您有很多要比较的值的原因是您使用一个查询的结果来创建下一个。当然,这应该通过连接而不是动态查询来解决:

select
  doc_text.doc_id, doc_text.language, doc_text.author, doc_text.title,
  doc_ref.ref_id, ref_master.location_id, location.location_display_name,
  doc_index.doc_id, doc_index.display_heading
from DOC_TEXT
inner join DOC_REF on doc_text.doc_id = doc_ref.doc_id
inner join REF_MASTER on doc_ref.doc_id = ref_master.ref_id
inner join LOCATION on ref_master.location_id = location.location_id
inner join DOC_INDEX on doc_text.doc_id = doc_index.doc_id
where
  doc_text.language in ('fr', 'es')

答案 3 :(得分:0)

我认为你真正的问题是你没有加入表格。

这是一个猜测,但我敢打赌你运行一个查询,然后获取你的应用程序中的所有ID,然后运行另一个查询WHERE所有行与上一个查询匹配。通过使用连接编写查询,可以大大提高性能:

SELECT
    *
    FROM YourTableA            a
        INNER JOIN YourTableB  b ON a.ID=b.ID
    WHERE a. .....
然后

处理应用程序中的单个结果集。