문제

저는 상대 초보자에 올 때 데이터베이스가 있습니다.우리가 사용하는 MySQL 고 내가 하려는 현재 속도 SQL 문을 것으로 보인다 가는 동안 실행됩니다.나는 주변에서도 비슷한 질문을 찾을 수 없다.

목표를 제거하는 모든 행 테이블이 있는 id 가 일치하는 테이블 B.

나는 현재 다음과 같다:

DELETE FROM a WHERE EXISTS (SELECT b.id FROM b WHERE b.id = a.id);

약 100K 행 테이블과에 대한 22K 행 테이블 b.열'id'PK 모두에 대한 테이블이 있습니다.

이 문을 약 3 분 정도 걸립니다 실행하는 테스트-Pentium D,XP SP3,2GB ram,MySQL5.0.67.이 보인다 느리게 나입니다.어쩌면 그것은 아니지만 내가 바라고 사용합니다.더 나은/빠른 방법으로 수행하는 이?


편집:

몇 가지 추가 정보는 것이 도움이 될 수도 있습니다.테이블을 A 와 B 가 같은 구조로 나는 다음과 같은 테이블을 만들기 위한 B:

CREATE TABLE b LIKE a;

테이블(고,따라서 테이블 b)몇 가지 인덱스 쿼리 속도를 높이기 위해 만들어진다.다시,나는 상대 초보 DB 작동하고 여전히 학습합니다.저는 얼마나 많이 알고하지 않의 효과,어떤 경우에는,이것은 것들입니다.나는 가정 하는 것 그것은 효과로 인덱스 작업을 수행할 수 있죠?또한 궁금하는 경우가 있었는 다른 DB 를 설정에 영향을 미칠 수 있는 속도입니다.

또한,나를 사용하여 이노 DB.


여기에 몇 가지 추가 정보는 것이 도움이 될 수 있습니다.

테이블 이와 유사한 구조를 가지고있다이(나는 소독이트):

DROP TABLE IF EXISTS `frobozz`.`a`;
CREATE TABLE  `frobozz`.`a` (
  `id` bigint(20) unsigned NOT NULL auto_increment,
  `fk_g` varchar(30) NOT NULL,
  `h` int(10) unsigned default NULL,
  `i` longtext,
  `j` bigint(20) NOT NULL,
  `k` bigint(20) default NULL,
  `l` varchar(45) NOT NULL,
  `m` int(10) unsigned default NULL,
  `n` varchar(20) default NULL,
  `o` bigint(20) NOT NULL,
  `p` tinyint(1) NOT NULL,
  PRIMARY KEY  USING BTREE (`id`),
  KEY `idx_l` (`l`),
  KEY `idx_h` USING BTREE (`h`),
  KEY `idx_m` USING BTREE (`m`),
  KEY `idx_fk_g` USING BTREE (`fk_g`),
  KEY `fk_g_frobozz` (`id`,`fk_g`),
  CONSTRAINT `fk_g_frobozz` FOREIGN KEY (`fk_g`) REFERENCES `frotz` (`g`)
) ENGINE=InnoDB AUTO_INCREMENT=179369 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

내가 의심되는 부분의 문제가 있의 숫자 인덱스 테이블.테이블 B 와 비슷한 테이블 B 지만,그것만이 열을 포함합 idh.

또한,이 프로파일링 결과는 다음과 같습니다:

starting 0.000018
checking query cache for query 0.000044
checking permissions 0.000005
Opening tables 0.000009
init 0.000019
optimizing 0.000004
executing 0.000043
end 0.000005
end 0.000002
query end 0.000003
freeing items 0.000007
logging slow query 0.000002
cleaning up 0.000002

해결

덕분에 모두 응답니다.그들은 확실히 나에 대해 생각하는 문제입니다.페 dotjoe 나를 점점 멀리 단계에서 문제가 요청에 의해 간단한 질문이"무엇이든 기타 테이블 참조.id?"

문제가 있었다는 삭제를 트리거하 테이블에 있는 이라고 저장 프로시저를 업데이트하는 두 개의 다른 테이블,C 및 D표 C FK 다시.id 와 일 후에 어떤 물건에 관련된 id 를 저장된 절차로,그것의 문,

DELETE FROM c WHERE c.id = theId;

동물이 어미가 총을 맞았기 때문에 왔명 문을 했고 이로,

EXPLAIN SELECT * FROM c WHERE c.other_id = 12345;

그래서 내가 볼 수있는 무엇이었고 그것은 나에게 다음과 같은 정보:

id            1
select_type   SIMPLE
table         c
type          ALL
possible_keys NULL
key           NULL
key_len       NULL
ref           NULL
rows          2633
Extra         using where

이것이 저에게 말하는 그것이 고통스럽게 만들어주는 수술을,그 때부터 얻을 것이라고 22500 시간(지정한 설정되는 데이터의 삭제),는 문제입니다.면 내가 만들어진에 인덱스는 other_id 열고 재실행하고 다 설명하고,나는:

id            1
select_type   SIMPLE
table         c
type          ref
possible_keys Index_1
key           Index_1
key_len       8
ref           const
rows          1
Extra         

더 나은 사실이 정말 좋습니다.

가는 Index_1 및 삭제 내 시간이 라인에서 시간에 의해 보고 mattkemp.이 미묘한 오류가에 나 때문에 부분적으로 신발-horning 일부 추가적인 기능이 있습니다.그는 대부분의 제안/삭제 SELECT 로 다니엘 시 위 기본적으로 같은 양의 시간과로 soulmerge 언급한 문 꽤 많이 되었을 것 수성 기반으로하세요.면 나는 인덱스를 제공합이 다른 표 C,삭제 내했다 빠르다.

사후:
두 가지 교훈이 나서 이 운동입니다.첫째로,그것은 분명하지 않았던 전력을 활용하의 설명 문 좋은 아이디어를 얻을 수의 영향의 내 SQL 쿼리를 처리합니다.는 신인 실수를,그래서 나는 자신을 이길 수에 대한 것을 하나입니다.나는 실수에서 배울.둘째로,문제가 되는 코드의 결과였다'그것을 얻을 완료 빠른'정신적인 디자인/테스트를 통해 이 문제를 보이지 않습니다.내가 생성되는 여러 가지 상당한 테스트 데이터 세트로 사용하 테스트 입력에 대한 이 새로운 기능을 죽이려고 했는데 낭비하지 않는 나의 시간도 당신입니다.내에서 테스트 DB 측면 부족한 깊이 있는 내용면에서는 장소입니다.지금 나는 개선 할 수있는 기회를니다.

참고:설명 Statement

도움이 되었습니까?

해결책

에서 데이터를 삭제하 InnoDB 은 가장 비용이 많이 드는 작업을 요청할 수 있습니다.당신은 이미 발견한 쿼리 자체가 문제가-그들의 대부분의 최적화하는 동일한 실행 계획 anyway.

는 동안 그것은 어려울 수 있습니다 이유를 이해하기 삭제하는 모든 케이스의 가장 느린,거기에 간단한 설명이 있습니다.InnoDB 은 트랜잭션 스토리지 엔진.는 것을 의미하는 경우 쿼리를 중단되었습니다 중간-을 통해,모든 레코드가 여전히 장소에 있으면 아무 일도 없었다.그것이 완료되면 모든 사라질 것 같습니다.안 삭제 기타 클라이언트가 서버에 연결하는 것이 기록을 볼 때까지 귀하의 삭제를 완료됩니다.

이를 달성하기 위해,InnoDB 기술을 사용하여 라는 MVCC(다중 버전의 동시성 제어).그것이 무엇이 기본적으로 제공하는 것입 각 연결은 스냅샷을 보기 전체의 데이터베이스로 첫 번째 문의 트랜잭션 시작했다.이를 달성하기 위해,모든 레코드에서 InnoDB 내부적으로 다수의 값을 가질 수 있습-각각합니다.이것은 또한 이유에 계산 InnoDB 약간의 시간이 소요에 따라 달라집니다-스냅샷 상태에 당신이 볼 수있는 시간입니다.

에 대한 삭제 트랜잭션,각각의 기록을 확인에 따라 쿼리 조건을 가져옵 삭제하도록 표시됩니다.으로 다른 클라이언트가 될 수 있습에 액세스하는 데이터 같은 시간에,그것은 할 수 없습 테이블에서 제거해야하기 때문에 그들의 각각의 스냅샷을 보장하는 원자성의 삭제합니다.

모든 레코드를 표시 삭제할 트랜잭션이 성공적으로 최선을 다합니다.그럼에도 그들할 수 없는 즉시 제거에서 실제 데이터 페이지를하기 전에,모든 거래는 일으로 스냅샷 값 앞에 삭제할 트랜잭션으로 끝났습니다.

그래서 사실의 3 분의하지 않은 정말로 느린,는 사실을 고려하여 모든 레코드를 수정해야기 위해 그들을 준비하 제거를 위한 트랜잭션에서 안전한 방법입니다.아마 당신은"듣고"너의 하드 디스크 작동하는 동안 문을 실행합니다.이로 인해 발생에 액세스하는 모든 행이 있습니다.성능 개선을 위해 당신을 높이기 위해 시도 할 수 있습니다 InnoDB buffer pool size 서버에 대한 제한하려고 다른 데이터베이스에 액세스할 수 있는 동안 당신을 삭제하여도의 수를 줄이는 역사적인 버전 InnoDB 은 유지됩니다.추가 메모리 InnoDB 을 읽을 수 있습니다 당신의 테이블(대부분)으로 메모리고 피부 디스크를 찾는다.

다른 팁

당신의 시간의 세 분 것이 정말로 느립니다.나의 추측은 id 열은 색인이 생성되지 않습니다.는 경우 제공할 수 있는 정확한 테이블의 정의를 사용하는 것이 도움이 될 것입니다.

내가 만들어 간단한 python 스크립트를 생성 테스트 데이터와 실 여러 개의 서로 다른 버전을 삭제에 대한 쿼리를 동일한 데이터를 설정합니다.여기 나의 정의 테이블:

drop table if exists a;
create table a
 (id bigint unsigned  not null primary key,
  data varchar(255) not null) engine=InnoDB;

drop table if exists b;
create table b like a;

그때 나는 삽입 100k 행로와 25k 행 b(22.5k 의도에서).여기 결과의 다양한 삭제 명령입니다.내가 떨어졌고 다시 채워 테이블 사이에 실행됩니다.

mysql> DELETE FROM a WHERE EXISTS (SELECT b.id FROM b WHERE a.id=b.id);
Query OK, 22500 rows affected (1.14 sec)

mysql> DELETE FROM a USING a LEFT JOIN b ON a.id=b.id WHERE b.id IS NOT NULL;
Query OK, 22500 rows affected (0.81 sec)

mysql> DELETE a FROM a INNER JOIN b on a.id=b.id;
Query OK, 22500 rows affected (0.97 sec)

mysql> DELETE QUICK a.* FROM a,b WHERE a.id=b.id;
Query OK, 22500 rows affected (0.81 sec)

모든 테스트에서 실행되었는 인텔 코어 2quad-core2.5GHz,2GB RAM Ubuntu8.10 및 MySQL5.0.참고 실행되는 하나의 sql 문을 여전히 하나의 스레드입니다.


업데이트:

업데이트 내 검사를 사용하 itsmatt 의 스키마에 있습니다.나는 약간 수정하여 그것을 제거 자동 증가(나를 생성 합성 데이터)및 캐릭터 설정 인코딩(작동하지 않는 관계가 없으로 발굴하고 그것).

여기에 내 새로운 테이블을 정의:

drop table if exists a;
drop table if exists b;
drop table if exists c;

create table c (id varchar(30) not null primary key) engine=InnoDB;

create table a (
  id bigint(20) unsigned not null primary key,
  c_id varchar(30) not null,
  h int(10) unsigned default null,
  i longtext,
  j bigint(20) not null,
  k bigint(20) default null,
  l varchar(45) not null,
  m int(10) unsigned default null,
  n varchar(20) default null,
  o bigint(20) not null,
  p tinyint(1) not null,
  key l_idx (l),
  key h_idx (h),
  key m_idx (m),
  key c_id_idx (id, c_id),
  key c_id_fk (c_id),
  constraint c_id_fk foreign key (c_id) references c(id)
) engine=InnoDB row_format=dynamic;

create table b like a;

나는 다음을 재실행과 동일한 테스트 100k 에서 행하고 25k 행 b(그리고 다시 채우기 사이에 실행).

mysql> DELETE FROM a WHERE EXISTS (SELECT b.id FROM b WHERE a.id=b.id);
Query OK, 22500 rows affected (11.90 sec)

mysql> DELETE FROM a USING a LEFT JOIN b ON a.id=b.id WHERE b.id IS NOT NULL;
Query OK, 22500 rows affected (11.48 sec)

mysql> DELETE a FROM a INNER JOIN b on a.id=b.id;
Query OK, 22500 rows affected (12.21 sec)

mysql> DELETE QUICK a.* FROM a,b WHERE a.id=b.id;
Query OK, 22500 rows affected (12.33 sec)

당신이 볼 수 있듯이 이것은 매우보다 조금 느리게 작동하기 전에,아마 때문에 여러 인덱스입니다.그러나,그것은 아무데도 거의 세습니다.

다른 뭔가가는 당신은 수도에서 보고 싶은 이동 longtext 분야의 끝에 스키마.내가 기억하는 것 같 mySQL 수행하는 더 나은 경우 모든 크기 제한된 필드를 먼저 및 텍스트,blob,등이 있습니다.

이것을 보십시오:

DELETE a
FROM a
INNER JOIN b
 on a.id = b.id

를 사용하여 하위 느린 경향이가 그대로 실행에 대한 각각의 레코드 외부에서 쿼리가 있습니다.

이것은 내가 항상 수행하고 있으로 작동하는 슈퍼 큰 데이터(여기:샘플 테스트는 테이블 150000 행):

drop table if exists employees_bak;
create table employees_bak like employees;
insert into employees_bak 
    select * from employees
    where emp_no > 100000;

rename table employees to employees_todelete;
rename table employees_bak to employees;

이 경우에는 sql 필터 50000 행으로 백업 테이블.쿼리 폭포에서 수행 내 느린 컴퓨터에서 5 초입니다.대체할 수 있으로 삽입 선택하여 자신의 필터 쿼리가 있습니다.

트릭을 수행하량 삭제에 큰 데이터베이스!;=)

당신이 당신의 하위에서'b'모든 행에 대해'a'.

Try:

DELETE FROM a USING a LEFT JOIN b ON a.id = b.id WHERE b.id IS NOT NULL;

이것을보십시오:

DELETE QUICK A.* FROM A,B WHERE A.ID=B.ID

그것은 훨씬 더 빠르게 정상적인 쿼리를 처리합니다.

참조 Syntax: http://dev.mysql.com/doc/refman/5.0/en/delete.html

내가 이것을 알고있었던 거 해결 때문에 OP 의 인덱싱 누락 하지만 나는 다음과 같이 추가적 조언이 유효하며,이는 보다 일반적인 경우 이 문제를 해결합니다.

나 개인적으로 처리하는 데에서 행을 삭제 하나의 테이블에 존재하는 또 다른 내 경험에 그것이 수행하기 위해 최선을 다음과 같은 경우에 특히 많이 기대의 행 삭제 될 수 있습니다.이 기술은 가장 중요한 것은 향상됩 복제 슬레이브 지연,이상과 같이 각 단일테이터 쿼리가 실행이 더 지연 것(복제는 하나의 스레드).

그래서,그것은 여기: 지를 선택하는 첫째로,별도의 쿼리, 기억,Id 반환에서 스크립트/응용 프로그램,그 후 계속에서 삭제하는 배치에서(예를 들어,50,000 시간).이를 달성하기 위해 다음과 같은:

  • 각각의 하나 삭제 문을 잠그지 테이블에 대한 너무 오래서에 따라 허 복제연을 얻을 제어.그것은 특히 중요에 의존하는 경우에는 복제를 제공하는 당신은 상대적으로--날짜 데이터입니다.의 혜택을 사용하여 일괄적은 찾을 경우 각 삭제 쿼리도 너무 오래 걸리를 조정할 수 있습니다 그것은 작은 것을 건드리지 않고 DB 구조입니다.
  • 의 또 다른 혜택을 사용하여 별도의를 선택하는 선택 자체에는 오랜 시간이 걸릴 수 있습하여 실행, 특히,수 없는 경우 어떤 이유로 사용하고 최고의 DB 인덱스입니다.선택은 내부를 삭제할 때,전체 문 마이그레이션 노예들은 그것을 해야 할 것이 모두 선택,또 다시 잠재적으로 뒤쳐지는 노예가 있기 때문에를 선택합니다.슬레이브 지연,다시,겪고 있다.사용하는 경우에는 별도의 쿼리를 선택하는 이 문제를로,모든 당신이 통과 목록의 Id 입니다.

알려가 있는 경우에 결함 나의 논리 곳이다.

더 많은 토론에 복제연과 싸우는 방법은 다음과 같이 하나를 참조하십시오 MySQL 슬레이브 지연(Delay)설명된 7 가지 방법을 배틀 그

P.S.한 가지에 관하여 주의깊은 물론,잠재적인 편집 테이블 사이의 시간은 선택이 완료 및 삭제를 시작합니다.나는 당신이 당신들은 이러한 정보를 사용하여 트랜잭션 및/또는 논리에 관련된 응용 프로그램입니다.

DELETE FROM a WHERE id IN (SELECT id FROM b)

어쩌면 당신은 다시 작성해야합 indicies 실행하기 전에 이러한 휴 쿼리가 있습니다.만,당신은 다시 작성하기로 하였습니다.

REPAIR TABLE a QUICK;
REPAIR TABLE b QUICK;

한 후 실행 위의 질문(예)

DELETE FROM a WHERE id IN (SELECT id FROM b)

쿼리 자체에서 이미 최적의 형태로,업데이트 인덱스 원인 전체 작업을 하는 길이입니다.수 비활성화 열쇠 에는 테이블 작동하기 전에,그 속도를해야한다는 것입니다.을 다시 설정할 수 있습에 나중에 시간이 필요하지 않다면 즉시 그들을.

다른 방법이 될 추가 deleted 깃발이 열 귀하의 테이블과 조정하는 다른 쿼리 그래서 그들은 그 가치 있습니다.가장 빠르 boolean 유형에 mysql 가 CHAR(0) NULL (=true",false=NULL).는 것이 빠른 작업을 삭제할 수 있습니는 값이다.

같은 생각을 표현에서 sql 문을:

ALTER TABLE a ADD COLUMN deleted CHAR(0) NULL DEFAULT NULL;

-- The following query should be faster than the delete statement:
UPDATE a INNER JOIN b SET a.deleted = '';

-- This is the catch, you need to alter the rest
-- of your queries to take the new column into account:
SELECT * FROM a WHERE deleted IS NULL;

-- You can then issue the following queries in a cronjob
-- to clean up the tables:
DELETE FROM a WHERE deleted IS NOT NULL;

는 경우에도,당신이 무엇을 원한다면,당신은 무엇인지 살펴보십시오 mysql 문서에 대해 말해야 속도 delete.

BTW,후 게시 위에 나 블로그 남 Schwartz 에서 Package 를 그 maatkit 이미 있는 도구는 이러한 목적을 위해-mk-archiver. http://www.maatkit.org/doc/mk-archiver.html.

그것은 대부분의 작업을 위한 최고의 도구.

분명 SELECT 는 쿼리를 구축의 기초 DELETE 작업은 매우 빠른 그래서 내가 생각하는 것 중 하나가 외국인 핵심 제약 조건이나 인덱스는 이유에 대한 매우 느리게 쿼리가 있습니다.

SET foreign_key_checks = 0;
/* ... your query ... */
SET foreign_key_checks = 1;

이것을 사용하여 사용하지 않도록 검사에서 외국인 핵심이다.불행하게도 당신을 사용하지 않도록 설정할 수 없(적어도 난 알 수 없는 방법)키 업데이트 InnoDB 테이블.로 MyISAM 테이블을 할 수 있는 뭔가

ALTER TABLE a DISABLE KEYS
/* ... your query ... */
ALTER TABLE a ENABLE KEYS 

실제로 테스트하지 않았다면 이 설정에 영향을 미칠 것이 쿼리 시간.하지만 그것은 시도 가치가있다.

에 연결 datebase 터미널을 사용하여 명령을 수행합니다 아래에서 보면,그 결과 그들 각각의 시간이,당신은 시간의 삭제 10,100,1000,10000,100000 기록하지 않은 곱해집니다.

  DELETE FROM #{$table_name} WHERE id < 10;
  DELETE FROM #{$table_name} WHERE id < 100;
  DELETE FROM #{$table_name} WHERE id < 1000;
  DELETE FROM #{$table_name} WHERE id < 10000;
  DELETE FROM #{$table_name} WHERE id < 100000;

의 시간을 삭제하 10 천 기록되지 않은 10 배나 많이 삭제는 100 만 기록합니다.다음을 제외하고,방법을 찾는 기록을 삭제하는 더 빠르고,거기에 몇 가지 간접적인 방법입니다.

1,우리 이름을 바꿀 수 있습 table_name 을 table_name_bak 를 선택한 다음 레코드에서 table_name_bak 을 table_name.

2,삭제 10000 기록,우리는 우리를 삭제할 수 있습 1000 기록 10.예있 루비 스크립트는 그것을 할 수 있습니다.

#!/usr/bin/env ruby
require 'mysql2'


$client = Mysql2::Client.new(
  :as => :array,
  :host => '10.0.0.250',
  :username => 'mysql',
  :password => '123456',
  :database => 'test'
)


$ids = (1..1000000).to_a
$table_name = "test"

until $ids.empty?
  ids = $ids.shift(1000).join(", ")
  puts "delete =================="
  $client.query("
                DELETE FROM #{$table_name}
                WHERE id IN ( #{ids} )
                ")
end

기본적인 기술을 삭제하는 여러 행 양식 MySQL 에서 한 테이블을 통해 id 분야

DELETE FROM tbl_name WHERE id <= 100 AND id >=200; 이 쿼리에 대한 책임이 삭제 일치하는 조건 100 200 에서 특정 테이블

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top