UNION 명령의 일반적인 MySQL 오류
Incorrect usage of UNION and ORDER BY
이 문제를 해결하기 위해서는 select 문을 괄호(parenthesis) 로 감싸주어야 합니다.
(SELECT col1,col2,col3 FROM table1)
UNION
(SELECT cola,colb,colc FROM table2)
Incorrect usage of UNION and ORDER BY
(SELECT col1,col2,col3 FROM table1)
UNION
(SELECT cola,colb,colc FROM table2)
Max connections 에러가 발생하면 PHP페이지에 Too many connection가 나옵니다.
이는 mysql에서 동시열결가능한 클라이언트수를 넘었기 때문이다.
이런에러의 원인으로는 다음과 같습니다.
1) mysql_connect()함수로 DB connect를 했다면 해당스크립트가 종료됨과 동시에 mysql_close()함수를 호출하지않아도 자동으로 연결이 종료된다.
하지만, mysql_pconnect()함수는 해당스크립트가 종료된후 mysql_close()함수가 호출되었더라도 연결이 끊어지지않은채로 계속 연결을 유지하고 있어서 금방 커넥션을 다채울수도 있다.
2) MySQL 의 메뉴얼을 보면 mysql_connect()함수를 사용하면 해당스크립트의 종료와 함께 연결이 종료된다고 되어있지만 ./mysqladmin -u -p processlist라는 명령어를 통해서 살펴보면 그대로 살아 있음을 알수 있다.
맨위에서 살펴보았던 mysqladmin -u -p variables의 결과로서 볼수 있는 여러가지 시작옵션들중 wait_timeout 의 값만큼 서버에 그대로 연결을 유지한채로 남아 있는 것이다.
따라서, 이것이 too many connections의 직접적인 이유인 것이다.
[콘솔에서 커넥션수 알아내기]
$ mysqladmin -u root -p variables | grep max_connection
| max_connections | 100
[mysql에서 커넥션수 알아내기]
show variables like '%max%';
이제는, 클라이언트의 동시 접속자를 늘리는 명령이다.
먼저 mysql을 데몬을 kill 합니다.다시 아래와같이 서버를 재가동한다.
#mysqld_safe --language=korean --datadir=/data --user=mysql --default-character-set=euc_kr -O max_connections=256 -O table_cache=128 -O wait_timeout=60 &
#mysqld_safe -O max_connections=256 -O table_cache=128 -O wait_timeout=60 &
참고로, 리눅스나 솔라리스 계열에서는 클라이언트의 동시 접속자수가 500 ~ 1,000 까지 가능하다고 합니다.하지만 1000 설정 하려고 해도 4way cpu에 상당히 많은 램이 필요하다고 할고 있다.
256이 적당하다.
여기서 max_connections 는 mysql 에 접속 할 수 있는 최대 사용자를 가르키며...
wait_timeout 은 접속 후 연결을 지속시키는 시간을 말한다
이렇게 하신 후 다시 확인한다.
[콘솔에서]
$ mysqladmin -u root -p variables | grep max_connection
$ mysqladmin -u root -p variables | grep wait_timeout
[mysql에서]
mysql> show variables like '%max_connection%';
mysql> show variables like 'wait_timeout';
[커넥션 확인]
mysql> show full processlist
[출처] mysql-too many connection|작성자 요루짱
MySQL 설정 파일(my.cnf or my.ini) 에 직접 추가 한 다음 재실행을 하셔도 적용이 됩니다.
[mysqld]
max_connections = 256
table_cache = 128
wait_timeout = 60
우분투 서버의 경우 mysql 원격 접속을 하기 위해서
/etc/mysql/my.cnf 파일의 bind-address 부분은 주석처리해준다
#
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
#bind-address = 127.0.0.1
#
우분투를 설치시 mysql character set 은 latin1 으로 되어 있기 때문에 my.cnf 파일에
다음 항목을 추가 하거나 수정해준다. 빨간 부분은 추가된 부분, 파란색 부분은 수정한 부분
----------------------------------------------------------
[client]
port = 3306
socket = /var/run/mysqld/mysqld.sock
default-character-set = euckr
[mysqld]
language = /usr/share/mysql/korean
character-set-client-handshake=FALSE
init_connect="SET collation_connection = euckr_korean_ci"
init_connect="SET NAMES euckr"
default-character-set = euckr
character-set-server = euckr
collation-server = euckr_korean_ci
[mysqldump]
default-character-set = euckr
[mysql]
default-character-set = euckr
-----------------------------------------------
mysql> ALTER DATABASE [Database] DEFAULT CHARACTER SET utf8;
mysql> ALTER TABLE [Table] DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
# cd /usr/local/mysql/bin //mysql이 설치된 디렉토리의 bin
# killall mysqld
# ./safe_mysqld --skip-grant &
# mysql
mysql> use mysql;
mysql> update user set password=PASSWORD('패스워드') where user='root';
mysql> flush privileges;
mysql> quit;
# killall mysqld
# ./safe_mysqld -uroot &

전 부터 인수관련 기사들이 나오긴했었나 보네요..
인수관련 기사를 접해 보지 못한터라.... ^^
오늘 인수완료 되었다는 기사가 나왔다길래.. ㅎㅎ
Integer Type
- TINYINT 128부터 127 까지의 정수형 타입, 부호가 없는 정수 0∼255까지 지원Stirng Type
-CHAR(m) 0~255까지 입력이 가능하며, 길이가 m길이만큼 고정 사이즈가
된다.
-VARCHAR (m)0~255까지 입력은 가능하지만, 길이는
고정이 아닌 가변 사이즈이다.
-BINARY(m) 이진 데이터를 바이트 지정한 만큼 고정
길이
-VARBINARY(m) 이전 데이터를 바이트 지정한 만큼
넣는다. 가벼 길이
-TINYBLOB 이전 데이터를 최대 255자까지 입력이
가능하다
-BLOB
최대 길이가 63535인 문자를 저장
-TEXT
최대 길이가 63535인 문자를 저장
-MEDIUMBLOB
최대 길이가 16777215인 문자를 저장
-LONGBLOB 최대 입력이 4G 이진데이타, 최대 2^32
바이트
-LONGTEXT 최대 입력이 4G 1바이트 문자열, 최대
2^32 자
/* Point */
- BLOB타입은 대소문자를 구분하고 TEXT타입은 대소문자를 구분하지 않는점이 틀림
- MySQL 3.23.2이번 버전에서는 BLOB와 TEXT컬럼에는 인덱스를 만들수 없다
- BLOB와 TEXT컬럼의 저장시에 문자열 됫부분의 공백이 제거되지 않는다.
- BLOB와 TEXT컬럼은 DEFAULT를 지정할 수 없다.
Data Type
-DATE
날짜를 표현하는 유형 [YYYY-MM-DD], 1000-01-01 ∼ 9999-12-31까지 나타낼 수 있다
-DATETIME
날짜와 시간을 표현하는 유형 [YYYY-MM-DD HH:MM:SS], 1000-01-01 00:00:00 ∼ 9999-12-31 23:59:59
-TIMESTAMP
자동변경 컬럼 타입(4 Byte ), 1970-01-01 00:00:00부터 2037년 까지 표현
-TIME
시간을 표현하는 유형 [HH:MM:SS], 839:59:59 ∼ 833:59:59 까지 표현
-YEAR
년도를 표현하는 유형[기본적으로 4자리로 사용], 1901년 ∼ 2155년
출처 : http://www.xaprb.com/blog/2006/05/26/how-to-write-full-outer-join-in-mysql/
In this article I’ll show several ways to emulate a FULL OUTER join on a RDBMS
that doesn’t support it, as is the case with even the most recent
versions of MySQL. This useful query is surprisingly tricky to get
right.
A standard SQL FULL OUTER join is like a LEFT or RIGHT join, except that it includes all rows from both tables, matching them where possible and filling in with NULLs where there is no match. I’ll illustrate that for clarity. Here are two of my favorite tables, apples and oranges:
| Variety | Price |
|---|---|
| Fuji | 5.00 |
| Gala | 6.00 |
| Variety | Price |
|---|---|
| Valencia | 4.00 |
| Navel | 5.00 |
I’ll join them on price. Here is the left join:
select * from apples as a
left outer join oranges as o on a.price = o.price
| variety | price | variety | price |
|---|---|---|---|
| Fuji | 5 | Navel | 5 |
| Gala | 6 | NULL | NULL |
And the right join:
select * from apples as a
right outer join oranges as o on a.price = o.price
| variety | price | variety | price |
|---|---|---|---|
| NULL | NULL | Valencia | 4 |
| Fuji | 5 | Navel | 5 |
The FULL OUTER JOIN of these two tables, on price, should give the following result:
| variety | price | variety | price |
|---|---|---|---|
| Fuji | 5 | Navel | 5 |
| Gala | 6 | NULL | NULL |
| NULL | NULL | Valencia | 4 |
That’s the result I’ll be working toward in this article. Here is a script to create and populate the example tables, so you can follow along:
create table apples (variety char(10) not null primary key, price int not null);
create table oranges (variety char(10) not null primary key, price int not null);
insert into apples(variety, price) values('Fuji',5),('Gala',6);
insert into oranges(variety, price) values('Valencia',4),('Navel',5);
JOINs and a UNIONOne method to simulate a full join is to take the union of two outer joins, for example,
select * from apples as a
left outer join oranges as o on a.price = o.price
union
select * from apples as a
right outer join oranges as o on a.price = o.price
This gives the desired results in this case, but it isn’t correct
for all cases. Suppose there are duplicate records in the tables
(remove the primary key and insert twice to create this situation). UNION eliminates duplicates, which a full join doesn’t do. UNION ALL isn’t the right answer either, because it will cause spurious duplicates. In fact, UNION
generates two independent result sets and then combines them, so there
is no way to get around this, because the two result sets need to “know
about each other” to produce the right results.
There are legitimate cases where duplicate results are expected and correct. For instance, even when the rows are unique, selecting only certain columns, in which there are duplicates, could cause this situation. This doesn’t apply in relational theory, because a set never has duplicates no matter what, but it does in SQL.
UNION ALL and an exclusion joinOne way to make UNION include only the duplicates I want is to use an exclusion join to eliminate anything from the second result that is already included in the first, like this:
select * from apples as a
left outer join oranges as o on a.price = o.price
union all
select * from apples as a
right outer join oranges as o on a.price = o.price
where a.price is null;
This handles duplicate rows correctly and doesn’t include anything it shouldn’t. It’s necessary to use UNION ALL instead of plain UNION,
which would eliminate the duplicates I want to keep. This may be
significantly more efficient on large result sets, since there’s no
need to sort and remove duplicates.
There’s a case where UNION won’t work: older versions of MySQL don’t support it. All is not lost, though.
I’ve written several articles explaining how to start with a set of mutually exclusive numbers (which I informally call a “mutex table“), then use the mutual exclusivity of the numbers to join things together in interesting ways. This lets me simulate subqueries and unions on earlier versions of MySQL, for example. This approach seems like it might work well here, too. For the following queries I’ll assume my mutex table has the values 0 and 1. Here’s a baseline mutex query for these two tables:
select * from mutex
left outer join apples as a on i = 0
left outer join oranges as o on i = 1;
| i | variety | price | variety | price |
|---|---|---|---|---|
| 0 | Fuji | 5 | NULL | NULL |
| 0 | Gala | 6 | NULL | NULL |
| 1 | NULL | NULL | Valencia | 4 |
| 1 | NULL | NULL | Navel | 5 |
Of course this isn’t a full join. If I want to full join on price, naturally, I need to include price in the join criteria somewhere, and the query above doesn’t even mention the price. But it’s a starting point for tinkering.
The mutex values in the leftmost column, combined with the join
criteria, ensure that every row in the two tables gets included on its
own row. The mutual exclusivity causes the Navel row not to be matched
to the Fuji row, even though they have the same price. The correct
behavior of a full join on price is to “fill in” the NULL values where the prices are equal. This modification to the join criteria will fill it in:
select * from mutex
left outer join apples as a on i = 0
left outer join oranges as o on i = 1 or a.price = o.price;
The or a.price = o.price relaxes the mutual exclusivity, telling the join to keep the rows separated unless they have the same price:
| i | variety | price | variety | price |
|---|---|---|---|---|
| 0 | Fuji | 5 | Navel | 5 |
| 0 | Gala | 6 | NULL | NULL |
| 1 | NULL | NULL | Valencia | 4 |
| 1 | NULL | NULL | Navel | 5 |
That’s getting closer. There is a spurious row, though. The Navel
row at the bottom of the result set shouldn’t be there; it has already
been matched to the Fuji row earlier, so there’s no need to include it
with all those NULLs as though there were no matching row in apples. Can I eliminate the Navel row without eliminating the Valencia row?
That turns out to be harder to do. I stared at it for a while, thinking I could include a WHERE clause that would eliminate spurious rows based on the value of i, but after a bit I got a reality check: the row has already been included above, and WHERE clauses work a row at a time, so there’s no way to assert something about one row while applying the WHERE
clause to another row. This simple fact is all I needed to realize
there’s no way to eliminate the Navel row with the given information.
What I can do, though, is stack another copy of the apples table onto the right-hand side of the results thus far, matching them to the oranges values and confining them to rows with mutex value 1 instead of 0. Now I can write a WHERE clause to see if a row in the i = 1 part of the result set matches a row in the i = 0 part. I’ll write it without the WHERE clause to start:
select * from mutex
left outer join apples as a on i = 0
left outer join oranges as o on i = 1 or a.price = o.price
left outer join apples as a2 on i = 1 and a2.price = o.price;
| i | variety | price | variety | price | variety | price |
|---|---|---|---|---|---|---|
| 0 | Fuji | 5 | Navel | 5 | NULL | NULL |
| 0 | Gala | 6 | NULL | NULL | NULL | NULL |
| 1 | NULL | NULL | Valencia | 4 | NULL | NULL |
| 1 | NULL | NULL | Navel | 5 | Fuji | 5 |
Now there is a way to tell between the Navel row, which I don’t want, and the Valencia, which I do: the Navel has non-NULL values in the rightmost copy of apples, but the Valencia doesn’t. All I have to do is eliminate rows that have matching values:
select * from mutex
left outer join apples as a on i = 0
left outer join oranges as o on i = 1 or a.price = o.price
left outer join apples as a2 on i = 1 and a2.price = o.price
where o.price is null or a2.price is null
If the WHERE clause is hard to understand, perhaps it’s easier to think of it this way: where not(o.price is not null and a2.price is not null). Both clauses are identical; all I did was apply some boolean identities. Here is the result:
| i | variety | price | variety | price | variety | price |
|---|---|---|---|---|---|---|
| 0 | Fuji | 5 | Navel | 5 | NULL | NULL |
| 0 | Gala | 6 | NULL | NULL | NULL | NULL |
| 1 | NULL | NULL | Valencia | 4 | NULL | NULL |
That result has the correct rows, but it has some extra columns, which I don’t need. Here’s the final query:
select a.*, o.* from mutex
left outer join apples as a on i = 0
left outer join oranges as o on i = 1 or a.price = o.price
left outer join apples as a2 on i = 1 and a2.price = o.price
where o.price is null or a2.price is null
Remember, this can’t be done without the mutex table, because I need something to provide non-NULL values for every row; otherwise the joins would not include values where the leftmost table has no rows to contribute.
This technique works if there are duplicate rows, and works on older versions of MySQL, but is probably the least efficient of the three I’ve demonstrated here. As usual, which query is appropriate depends on circumstances.
+--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | euckr | | character_set_connection | euckr | | character_set_database | euckr | | character_set_results | euckr | | character_set_server | euckr | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | | collation_connection | euckr_korean_ci | | collation_database | euckr_korean_ci | | collation_server | euckr_korean_ci | | concurrent_insert | ON | | connect_timeout | 5 | +--------------------------+----------------------------+
CREATE TABLE t1 ( a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,message CHAR(20)) ENGINE=MyISAM;
CREATE TABLE t2 (
a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,message CHAR(20)) ENGINE=MyISAM;
INSERT INTO t1 (message) VALUES ('Testing'),('table'),('t1');
INSERT INTO t2 (message) VALUES ('Testing'),('table'),('t2');
CREATE TABLE total (a INT NOT NULL AUTO_INCREMENT,
message CHAR(20), INDEX(a))
ENGINE=MERGE UNION=(t1,t2) INSERT_METHOD=LAST;
t1, t2 테이블의 데이터를 total 테이블에 병합된 데이터로 insert 하게 된다.
NSERT_METHOD는 total 테이블에 다이렉트로 INSERT할경우 UNION에
정의한 테이블중 어느 테이블에 INSERT를 할건지 정의하는것이다.(FISRT or LAST)
※ 주의할점은 두 테이블의 레코드 형식 및 타입까지 모두 일치하여야 한다.
EXPLAIN tbl_name OR EXPLAIN SELECT select_options
tbl_name은 테이블의 구조를 나타냅니다.
EXPLAIN SELECT select_optionsEXPLAIN SELECT select_options