如何加快此查询?

时间:2011-05-31 01:59:36

标签: mysql sql query-optimization

我有一个包含60个属性的表,attribute1..attribute60。 MySQL中的数据库引擎和表引擎是MyISAM。查询如下:

SELECT DISTINCT attribute1
  FROM `product_applications`
 WHERE `product_applications`.`brand_id` NOT IN (642, 630, 513, 637, 632,
                                                 556, 548, 628, 651, 660,
                                                 648, 557, 650, 624, 652,
                                                 636, 546, 662, 634, 629,
                                                 657, 638, 658, 659, 661, 625)

我使用NOT IN,因为该列表明显小于IN列表。

我创建了以下索引:

brand_id, attribute1, attribute2, attribute3, attribute4

DESC显示正在选择此索引,但它看起来仍然在查看整个表,因为我在“行”列中看到整行计数:

6732948

在“额外”栏中,我有:

Using where; Using index; Using temporary

此查询需要7秒钟。我在这里看到所有不同的选项,包括打破桌面。

更新:

我能够通过巧妙地使用我朋友在下面注明的UNION ALL将查询时间缩短一半。此外,这是一个动态生成的查询,因此我可以使用你们中的一些人提供的临时表选项,这是一个很好的主意。

3 个答案:

答案 0 :(得分:2)

以前,以下使用LEFT JOIN - 但OP颠倒逻辑以使用INNER JOIN:

   SELECT DISTINCT 
          t.attribute1
     FROM PRODUCT_APPLICATIONS t
     JOIN (SELECT 642 AS brand_id
           UNION ALL 
           SELECT 630
           UNION ALL 
           SELECT 513
           UNION ALL 
           SELECT 637
           UNION ALL 
           SELECT 632           
           UNION ALL 
           SELECT 556
           UNION ALL 
           SELECT 548
           UNION ALL 
           SELECT 628
           UNION ALL 
           SELECT 651
           UNION ALL 
           SELECT 660
           UNION ALL 
           SELECT 648
           UNION ALL 
           SELECT 557
           UNION ALL 
           SELECT 650
           UNION ALL 
           SELECT 624
           UNION ALL 
           SELECT 652
           UNION ALL 
           SELECT 636
           UNION ALL 
           SELECT 546
           UNION ALL 
           SELECT 662
           UNION ALL 
           SELECT 634
           UNION ALL 
           SELECT 629
           UNION ALL 
           SELECT 657
           UNION ALL 
           SELECT 638
           UNION ALL 
           SELECT 658
           UNION ALL 
           SELECT 659
           UNION ALL 
           SELECT 661
           UNION ALL 
           SELECT 625) x ON x.brand_id = t.brand_id

您可以考虑填充temp table,以代替我在答案中看到的派生文件。

答案 1 :(得分:0)

[1] 642,630,513,637,632, 556,548,628,651,660, 648,557,650,624,652, 636,546,662,634,629, 657,638,658,659,661, 625

由于你已对其进行了硬编码,我认为这些是你想要一直排除的数字 那么,为什么不创建一个只包含这些id的表,另一个表不包含这些id。并且,您的插入基于'brand_id'确定要插入哪个表。

[2] 662,661,660,659,658,657,652,651,650,648,642,638,637,636,634,632,630,629,628,625,624,557,556,548,546, 513

您的brand_ids的排序列表如上所示。看起来你可以通过提供范围条件来降低等式调用。 (即,> = = 657&&< = 662,> = 650&&< = 652等。)

答案 2 :(得分:0)

此查询中的长杆是“DISTINCT”子句。

首先,我不确定你为什么说“这是一个动态生成的查询,所以你们中有些人提供的临时表格选项都没有提供给我。”可以使用动态生成查询的临时表...?也许你的意思是别的。

你能为此至少建立一个支持表吗?类似的东西:

CREATE TABLE product_applications_brand_id_attribute1 (
    PRIMARY KEY (attribute1)
) IGNORE AS SELECT attribute1
FROM product_applications
WHERE brand_id NOT IN (
    642, 630, 513, 637, 632, 556, 548, 628, 651, 660,
    648, 557, 650, 624, 652, 636, 546, 662, 634, 629,
    657, 638, 658, 659, 661, 625)

然后,您将查询:

SELECT attribute1
    FROM product_applications_brand_id_attribute1

这不是一个理想的解决方案,因为每次基表发生更改时都必须更新新的单独表。