从 Oracle 合并到 MySQL - NPR 实例分析
从 Oracle 合并到 MySQL - NPR 实例分析
npr.org
Overview
Background Database Architecture SQL Differences Concurrency Issues Useful MySQL Tools Encoding Gotchas
Background
All Things Considered, Morning Edition, Fresh Air, Wait, Wait, Dont Tell Me, etc.
Broadcasted on over 800 local radio stations nationwide
Website (NPR.org) with audio content from radio programs Web-Only content including blogs, slideshows, editorial columns
Database Architecture
Content Mgmt System Main RO slave
Main Web Servers Read and updated only by our website InnoDB Low resource contention Main Updated by a nightly script Small tables or log tables RO slave Read-only by our Content Short Transactions Management System Need fast full text queries AMG STATIONS PUBLIC (replacing Oracle Text) MyISAM InnoDB InnoDB Large tables Isolation Updated from by main Content website Management System Updated by a our quarterly script Transaction Read-only by Oriented our Read-only from ourwebservers website Horizontally Resource Contention scalable Scripts Some log type information written Backup Highly Normalized Low resource contention RO slave No transactions
MySQL is case sensitive Oracle outer join syntax (+) -> OUTER JOIN clause Oracle returns a zero to indicate zero rows updated MySQL returns TRUE (1) to indicate it
MySQL sorts null to the top, Oracle sorts null to the bottom
Use order by colName desc for sorting asc with nulls at bottom
CREATE TABLE our_seq ( id INT NOT NULL ); INSERT INTO our_seq (id) VALUES (120000000);
SELECT LAST_INSERT_ID();
For updating many rows at once, get the total number of unique IDs you need first:
Then use the whole rownum workaround described above to get a unique value for each row:
. .
Converting Functions
NVL() -> IFNULL() or COALESCE() DECODE() -> CASE() or IF() Concatenating strings || -> CONCAT()
test || null returns test in Oracle CONCAT(test,null) returns null in MySQL Use LOCATE() for Oracles INSTR() with occurrences = 1. SUBSTRING_INDEX() and REVERSE() might also work.
Converting Dates
DATE_FORMAT
Update Differences
You can't update a table that is used in the WHERE clause for the update (usually in an "EXISTS" or a subselect) in mysql.
UPDATE tableA SET tableA.col1 = NULL WHERE tableA.col2 IN (SELECT tableA.col2 FROM tableA A2, tableB WHERE tableB.col3 = A2.col3 AND tableB.col4 = 123456);
We used GROUP_CONCAT() with an ORDER BY and GROUP BY to get a list in a single column over a window of data
Collation
You can set collation at the server, database, table or column level.
Changing the collation at a higher level (say on the database) wont change the collation for preexisting tables or column.
Backups will use the original collation unless you specify all the way down to column level.
Concurrency Issues
MySQL configuration
commit
transaction_isolation = READ-COMMITTED
MySQL Administrator
innotop
http://code.google.com/p/innotop
Helped us identify deadlocks and slow queries (dont forget the slow query log!)
In mysql, use
show engine innodb status\G;
Query Profiling
Try the Query Profiler with Explain Plan when debugging slow queries
http://dev.mysql.com/tech-resources/articles/usingnew-query-profiler.html
Concurrency Solution
Turns out that the RAID card we were using had no write cache at all. to go live. Fixing that allowed us
Encoding Gotchas
Issues with characters that actually were not ISO-8859-1 in our Oracle database
Lack of documentation for the LUA script produced by the migration GUI
Continuing Issues
Bugs with innodb locking specific records (as opposed to gaps before records)
Uncommitted but timed out transactions Use innotop or show engine innodb status\G; and look for threads waiting for a lock but no locks blocking them
Questions?