如何优化“IN”查询?

时间:2016-08-02 13:37:47

标签: mysql sql postgresql

****编辑****

14ms可能看起来不是很多,但是正如你在下面的“PostgresSQL Explain”中看到的那样,PostgreSQL正在对80,000行进行Seq扫描。必须有办法避免这种扫描并改为进行一些索引查找。

****编辑结束****

我正在玩无模式的想法,我有以下三个表:

表格中填入了100,000个随机条目。

$('input[type=checkbox]').click(function(){
    $(this).closest('tr')
    .find('input[type=checkbox]').not(this)
    .attr('disabled', this.checked);


    // Below is the added code
    var tdIndex = $(this).closest('td').index() + 1;
    $('table').find("tr td:nth-of-type(" + tdIndex + ")")
    .find('input[type=checkbox]').not(this)
    .attr('disabled', this.checked);

});

entities(_primary_key SERIAL PRIMARY KEY, _id CHAR(32) UNIQUE, data BYTEA) index_username_profile_names(_id CHARE(32) PRIMARY KEY, key VARCHAR UNIQUE) index_username_email(_id CHAR(32) PRIMARY KEY, key VARCHAR)

上使用非唯一索引

我的SQL查询是:

index_username_email(key)

虽然“test”不会在任何一个'index'表中退出,但无论我是使用PostgreSQL还是MySQL,这都需要14毫秒,所以它一定是我做错了。

知道如何优化它,或者我做错了什么?

谢谢!

Postgres解释:

SELECT data FROM entities WHERE 
  _id IN (SELECT _id FROM index_users_email WHERE key = 'test')
 OR 
  _id in (SELECT _id FROM index_users_profile_name WHERE key = 'test')

5 个答案:

答案 0 :(得分:1)

14毫秒很好。我不知道为什么你认为查询应该在不到一毫秒的时间内运行。设置查询,验证数据在内存中,识别索引的位置等等,有很多工作要做。我把它放在引号中,因为对于大多数查询来说,这是微不足道的。但它可以很容易地加起来毫秒。

其次,如果你正在做实时,请记住以下几点:

  • 计算机(因为我们使用它们)不是确定性的。您需要多次运行计时。对于需要几毫秒的事情,通常需要数千次来获得稳定的读数。
  • 将系统初始化为每个时间的相同状态。您需要确定是否需要冷缓存或热缓存,但时间应该都在同一系统上。
  • 将系统与任何其他工作隔离开来。后台任务(甚至移动鼠标)可能会影响性能。

就查询而言,我能想到的一件事是使用=exists

SELECT e.data
FROM entities e
WHERE _id = (SELECT _id FROM index_users_email WHERE key = 'test') OR 
      EXISTS (SELECT 1 FROM index_users_profile_name iupn WHERE iupn._id = e.id AND iupn.key = 'test');

但最好的情况是,我猜这些会使查询缩短一两毫秒。

答案 1 :(得分:1)

OR ed(join-)条件通常不好,请尝试UNION

SELECT data FROM entities 
WHERE _id IN 
 ( SELECT _id 
   FROM index_users_email 
   WHERE key = 'test'
 )
UNION
SELECT data FROM entities
WHERE _id in 
 ( SELECT _id 
   FROM index_users_profile_name 
   WHERE key = 'test'
 )

答案 2 :(得分:0)

SELECT data 
FROM entities e
    LEFT OUTER JOIN index_users_email iue ON e._id=iue._id and iue.key = 'test'
    LEFT OUTER JOIN index_users_profile_name iupn ON e._id=iupn._id and iupn .key = 'test'
WHERE 
  iue._id IS NOT NULL or iupn._id IS NOT NULL

答案 3 :(得分:0)

看起来一个可能的答案是unionjoin

explain select data from entities as t join (select _id from index_users_email where key = 'test' union select _id from index_users_profile_name where key = 'test') u on t._id = u._id;
                                                                QUERY PLAN                                                                 
-------------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=17.32..33.82 rows=2 width=163)
   ->  Unique  (cost=16.90..16.91 rows=2 width=33)
         ->  Sort  (cost=16.90..16.91 rows=2 width=33)
               Sort Key: index_users_email._id
               ->  Append  (cost=0.42..16.89 rows=2 width=33)
                     ->  Index Scan using index_users_email_key_idx1 on index_users_email  (cost=0.42..8.44 rows=1 width=33)
                           Index Cond: ((key)::text = 'test'::text)
                     ->  Index Scan using index_users_profile_name_key_idx1 on index_users_profile_name  (cost=0.42..8.44 rows=1 width=33)
                           Index Cond: ((key)::text = 'test'::text)
   ->  Index Scan using entities__id_key on entities t  (cost=0.42..8.44 rows=1 width=196)
         Index Cond: (_id = index_users_email._id)
(11 rows)

Time: 0.714 ms

答案 4 :(得分:0)

这将有更好的性能,因为它利用了这些表中的主键:

select data
from entities
where 
    exists (
        select _id
        from index_users_email
        where key = 'test' and _id = entities._id
    ) or exists (
        select _id
        from index_users_profile_name
        where key = 'test' and _id = entities._id
    )