doupang4126 2013-09-06 02:50
浏览 50
已采纳

MySQL PDO查询优化

I'm trying to reduce this script execution time. It queries a database with about 2 million records about 1000 times on a loop:

foreach ($ids as $id){
    $stmt=$dbh->query("SELECT SQL_CACHE * FROM `ids` 
                WHERE $id BETWEEN `id_start` AND `id_end`");
    $rows[] = $stmt->fetch();
}

It takes forever on a 4 core 8 GB machine (about 800 seconds!). Id groups do not overlap, ids tend to be from just a few different groups in each execution and I have indexed both (id_start,id_end) and (id_end).

Caching improves very much the situation (running the same 1000 values more than once is just a few seconds), but I would like to know what can I do to speed up non cached queries.

Example output of EXPLAIN:

"id"    "select_type"   "table"     "type"  "possible_keys"     "key"               "key_len"   "ref"   "rows"  "Extra"
"1"     "SIMPLE"        "ids"       "range" "id_start,id_end"   "id_start,id_end"   "5"          ""     "52508" "Using index condition"

EDIT: Instead of "Using index condition" I get "Using where" sometimes (Not sure but I think from id values higher than 840771583) Why?

EDIT 2: Full create code:

CREATE TABLE `ids` (
    `id_start` INT(10) UNSIGNED NULL DEFAULT NULL,
    `id_end` INT(10) UNSIGNED NULL DEFAULT NULL,
    `iso-639-1` VARCHAR(2) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
    `country_name` VARCHAR(64) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
    `region_name` VARCHAR(64) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
    `city_name` VARCHAR(64) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
    `area_code` VARCHAR(16) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
    `timezone` VARCHAR(6) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
    UNIQUE INDEX `id_startid_end` (`id_start`, `id_end`),
    INDEX `id_end` (`id_end`),
    INDEX `country_name` (`country_name`),
    INDEX `region_name` (`region_name`),
    INDEX `city_name` (`city_name`),
    INDEX `area_code` (`area_code`),
    INDEX `iso-639-1` (`iso-639-1`),
    INDEX `timezone` (`timezone`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB;
  • 写回答

2条回答 默认 最新

  • douju1968 2013-09-06 10:34
    关注

    Since the intervals do not overlap, try this rewriting of the query:

    SELECT * 
    FROM ids
    WHERE id_start =
          ( SELECT MAX(id_start) 
            FROM ids
            WHERE id_start <= $id
          )
      AND $id <= id_end ;
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 linux驱动,linux应用,多线程
  • ¥20 我要一个分身加定位两个功能的安卓app
  • ¥15 基于FOC驱动器,如何实现卡丁车下坡无阻力的遛坡的效果
  • ¥15 IAR程序莫名变量多重定义
  • ¥15 (标签-UDP|关键词-client)
  • ¥15 关于库卡officelite无法与虚拟机通讯的问题
  • ¥15 目标检测项目无法读取视频
  • ¥15 GEO datasets中基因芯片数据仅仅提供了normalized signal如何进行差异分析
  • ¥100 求采集电商背景音乐的方法
  • ¥15 数学建模竞赛求指导帮助