MySQL InnoDB tables vs. MyISAM tables


MySQL has multiple ways in which it can store your data, called storage engines. The two most commonly used engines are MyIASM and InnoDB; I have a hard time remembering which I wanted to use, and answering people when they ask why I used the type I did. So…

InnoDB tables support foreign keys; MyISAM does not. (ref)

“Full-text indexes can be used only with MyISAM tables”. (ref)

InnoDB supports transactions! Note autocommit is set by default. (ref)

Because MyISAM tables are non-transaction-safe they may be smaller, faster, and require less memory to update (ref).

The InnoDB engine also supports Clustered indexes, Data caches, and has finer locking granularity than MyISAM, although MyISAM does have something called “Geospatial indexing support.”

The official summaries:

MyISAM — The default MySQL storage engine and the one that is used the most in Web, data warehousing, and other application environments. MyISAM is supported in all MySQL configurations, and is the default storage engine unless you have configured MySQL to use a different one by default.

InnoDB — A transaction-safe (ACID compliant) storage engine for MySQL that has commit, rollback, and crash-recovery capabilities to protect user data. InnoDB row-level locking (without escalation to coarser granularity locks) and Oracle-style consistent non-locking reads increase multi-user concurrency and performance. InnoDB stores user data in clustered indexes to reduce I/O for common queries based on primary keys. To maintain data integrity, InnoDB also supports FOREIGN KEY referential-integrity constraints.



My First Mac


A little shy of a year ago I got my first Mac. I figured it would work well for business use: easy access to the command line and Unix core, but not requiring the fussing that Linux does.

Some things are surprisingly easy on the Mac:

  • set up desktop background image rotation
  • remap the keyboard (eg. capslock to control)
  • building presentations in Keynote

Many things are just downright impossible on the Mac:

  • open in one space an application which is already open in another space
  • alt-tab through applications just in the current space
  • hit the control key with your right hand (there is no control key on the right side of the keyboard)
  • change your username (you better get it right the first time)
  • eject a cd without powering on the computer (there is no pinhole eject)
  • resize a window from anywhere but the very bottom right-hand corner of the window (really annoying when that corner is off the screen or you just want to make a window taller)
  • “right-click” using just the keyboard (most laptops have a “right-click” key)
  • directly access a particular menu bar menu using just the keyboard
  • open a playlist in iTunes
  • use the keyboard to jump to the end of a row or column in Numbers
  • open a .log or .tab file in Numbers

Other annoyances:

  • closing the last window of a program doesn’t end the program
  • the program “Finder” is always open and running
  • although program windows can be moved to separate virtual desktops alt+tab always cycles through all open programs
  • ships with old versions of common UNIX tools such as grep

Things that are just kind of weird:

  • keyboard shortcuts are all rearranged

Configuration

Fix function keys
System Preferences -> Keyboard & Mouse -> Keyboard -> Use all F1, F2, etc. keys as standard function keys
Set touchpad tap to click
System Preferences -> Keyboard & Mouse -> Trackpad -> Tap to Click
set mouse to be two-button
System Preferences -> Keyboard & Mouse -> Mouse -> Secondary Button
Enable Secondary Click
System Preferences -> Keyboard & Mouse -> Trackpad -> Secondary Click
set mouse middle click to be button three
System Preferences -> Keyboard & Mouse -> Mouse -> Button 3
Set tracking speed (trackpad)
System Preferences -> Keyboard & Mouse -> Trackpad -> adjust Tracking Speed to Fast
Set tracking speed (mouse)
System Preferences -> Keyboard & Mouse -> Mouse -> adjust Tracking Speed to Fast
Enable Spaces
System Preferences -> Expose & Spaces -> Spaces -> Enable Spaces
Non-schizophrenic Zoom
System Preferences -> Keyboard & Mouse -> Trackpad -> Screen Zoom Options -> Only when the pointer reaches an edge
Allow browser to tab into all form elements
System Preferences -> Keyboard & Mouse -> Keyboard Shortcuts -> All Controls
Disable F-key hijacking
System Preferences -> Keyboard & Mouse -> Keyboard Shortcuts (uncheck as necessary)
Fix screen from auto-dimming every 1-2 minutes
Allow TextEdit to save .txt plaintext files
TextEdit -> Preferences -> Plain text
Date in Munu Bar
Use iStat Menus
Replace obsolete grep
Just download, build, install, and replace /usr/bin/grep with the new binary.

Some things you’ll need to know:
- Default document root is /Library/WebServer/Documents

Software

Cyberduck
For FTPing
Adium
All-purpose IM client
Eclipse
Firefox
Of course
GIMP
(but which build?)
Picasa
Otherwise there is no way to get photos off my digital camera
Skitch
The ultimate screenshot utility–more useful than you might think
Transmission>
For downloading large files quickly
VMWare Fusion

MacPorts Stuff

HexEdit
wget
phpMyAdmin
Subversion
MySQL

Start MySQL with /opt/local/lib/mysql5/bin/mysqld_safe &

The MySQL socket file is at /opt/local/var/run/mysql5/mysqld.sock

To start mysqld at boot time you have to copy support-files/mysql.server to the right place for your system

Apache

Document root is /opt/local/apache2/htdocs

The Apache config file is /opt/local/apache2/conf/httpd.conf

Comment out LoadModule ssl_module modules/mod_ssl.so in httpd.conf, since that seems to be broken in the MacPorts install.

Add these to your mimetypes:

AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps

Add index.php to the DirectoryIndex:


DirectoryIndex index.html index.php

alias apache2ctl='sudo /opt/local/apache2/bin/apachectl' and apache2ctl start to get started!

###########################################################
# A startup item has been generated that will aid in
# starting apache2 with launchd. It is disabled
# by default. Execute the following command to start it,
# and to cause it to launch at startup:
#
# sudo launchctl load -w /Library/LaunchDaemons/org.macports.apache2.plist
###########################################################


CodeIgniter Setup


CodeIgniter is a small and fast PHP framework. Not all of these steps are necessary to use the framework, but they result in a more secure setup where none of the framework files are ever web accessible.

  1. Download the .zip
  2. Create a public/ directory at the same level as the system/ directory containing asset directories: mkdir public public/images public/javascripts public/stylesheets
  3. Move the index.php file into the public/ directory: mv index.php public
  4. Edit the index.php file to reflect it’s new location: :%s/$system_folder = "system";/$system_folder = "..\/system";/
  5. Inside of system/application/config/config.php:
    1. Set the 'base_url' to your sites URL
    2. Clear the 'index_page' config (set it to the empty string)
    3. 'enable_query_strings' if necessary
    4. Adjust the 'log_threshold'
    5. Choose a unique 'encryption_key'
    6. Turn 'sess_encrypt_cookie' on
    7. At the end of config.php add:
      // optionally load (and potentially override) additional config values
      if (file_exists('../system/application/config/config.local.php'))
      {
          include('config.local.php');
      }
  6. Create (and promptly SVN ignore, if applicable) a config.local.php file. The file will usually only contain overrides for ‘base_url’, ‘index_page’, ‘log_threshold’, and ‘log_path’.
  7. Fill out the database.php config file as necessary, potentially with a companion database.local.php file as well.
  8. If you wish to remove the index.php from you URLs, create a .htaccess file like so:
    RewriteEngine On
    RewriteCond $1 !^(index\.php|images|stylesheets|javascripts|favicon\.ico|robots\.txt)
    RewriteRule ^(.*)$ /fresh/index.php/$1 [L]
  9. Point your document root to the new public/ directory and you’re off!


iPhone Apps


iPhone apps I use:

Cydia

Flashlight
iBlacklist
iGlassSol
PdaNet
SBSettings Location Toggle
WebSearch
WinterBoard

App Store

Amazon Mobile
BGG
Dictionary
Easy Wi-Fi for AT&T
Google Mobile App
Movies
Public Radio
The Scriptures
Urbanspoon
Wikiamo

Web Apps

http://m.rememberthemilk.com/ (http://ideaharbor.org/i/rtm/)

http://scripturesapp.com/

http://wsdot.wa.gov/small/ (http://ideaharbor.org/i/t/)



cron


Some useful cron commands:


59 15 * * 1,2,3,4,5 /usr/bin/streamripper http://128.208.34.80:8002/listen.pls -u 'iTunes/7.7.0' -d /path/to/destination/directory -a atc_`date +\%Y-\%m-\%d` -l 7320 >/dev/null 2>&1

This records “All Things Considered” from NPR each weekday afternoon, just like you used to record radio onto cassette tapes when you were a kid. If I remember correctly cron didn’t like the output streamripper generates while working, hence the redirect to /dev/null. The % character has some special significance to cron and thus must be escaped in the date sub-command.


58 20 * * 1,2,3,4,5 /usr/bin/streamripper http://www.wfuv.org/audio/wfuvmp3high.pls -u 'iTunes/7.7.0' -d /path/to/destination/directory/echoes -a echoes_`date +\%Y-\%m-\%d` -l 7380 >/dev/null 2>&1

Similarly, this records the radio show “Echoes”.


32 15,3 * * * cd /path/to/destination/directory && wget --mirror --wait 15 --random-wait --page-requisites --convert-links --no-parent --span-hosts --domains downloads.bfads.net,bfads.net --exclude-domains i.bfads.net,forums.bfads.net,m.bfads.net http://bfads.net/Adscans/

Each November http://bfads.net/ collects leaked circulars of upcoming Black Friday sales. Some of them are later removed after the stores whine, threaten, and complain. This command checks twice daily for new adscans and downloads an extra copy to a safe place.



Google Radar Charts


Some radar charts created using the Google Chart API.

Look at the image src URLs to see how each was constructed. If you have any cool radar charts I’d be happy to add them here.



MySQL Outer Joins Accross Multiple Tables


This is the third time in as many months that I’ve had to read the MySQL Reference Manual section on JOIN Syntax, so it’s time to summarize.

For example, let’s say you have tables:

books

+----+-----------------------------------------+-----------+
| id | title                                   | is_unread |
+----+-----------------------------------------+-----------+
|  1 | Ulysses                                 |         1 |
|  2 | The Great Gatsby                        |         0 |
|  3 | A Portrait of the Artist as a Young Man |         1 |
|  4 | Lolita                                  |         1 |
|  5 | Brave New World                         |         0 |
+----+-----------------------------------------+-----------+

tags

+----+------------+
| id | name       |
+----+------------+
|  1 | classic    |
|  2 | fiction    |
|  3 | irish      |
|  4 | dystopia   |
|  5 | literature |
+----+------------+

books_tags

+---------+--------+
| book_id | tag_id |
+---------+--------+
|       1 |      2 |
|       1 |      3 |
|       2 |      2 |
|       2 |      1 |
|       3 |      2 |
|       3 |      3 |
|       4 |      2 |
|       5 |      1 |
|       5 |      2 |
|       5 |      4 |
+---------+--------+

and we want to know how many books there are with each tag in the database. We could say

SELECT t.*, COUNT(bt.book_id)
FROM tags t
JOIN books_tags bt ON t.id = bt.tag_id
GROUP BY t.id;

and get

+----+----------+----------------+
| id | name     | count(book_id) |
+----+----------+----------------+
|  1 | classic  |              2 |
|  2 | fiction  |              5 |
|  3 | irish    |              2 |
|  4 | dystopia |              1 |
+----+----------+----------------+
4 rows in set (0.00 sec)

but we’re missing a tag! This is easily solved by using a LEFT JOIN, like so:

SELECT t.*, COUNT(bt.book_id)
FROM tags t
LEFT JOIN books_tags bt ON t.id = bt.tag_id
GROUP BY t.id;

+----+------------+----------------+
| id | name       | count(book_id) |
+----+------------+----------------+
|  1 | classic    |              2 |
|  2 | fiction    |              5 |
|  3 | irish      |              2 |
|  4 | dystopia   |              1 |
|  5 | literature |              0 |
+----+------------+----------------+
5 rows in set (0.00 sec)

But what if you only want to consider books you’ve read? Now we must also join against the books table.
You may be tempted to try

SELECT t.*, COUNT(bt.book_id)
FROM tags t
LEFT JOIN books_tags bt ON t.id = bt.tag_id
LEFT JOIN books b ON b.id = bt.book_id
WHERE is_unread = 0
GROUP BY t.id;

but that simply returns

+----+----------+----------------+
| id | name     | count(book_id) |
+----+----------+----------------+
|  1 | classic  |              2 |
|  2 | fiction  |              2 |
|  4 | dystopia |              1 |
+----+----------+----------------+

To return all tags the trick is to move the condition into the join clause and then count what’s returned from the third table. Thus

SELECT t.*, COUNT(b.id)
FROM tags t
LEFT JOIN books_tags bt ON t.id = bt.tag_id
LEFT JOIN books b ON b.id = bt.book_id AND b.is_unread = 0
WHERE 1 GROUP BY t.id;

+----+------------+-------------+
| id | name       | count(b.id) |
+----+------------+-------------+
|  1 | classic    |           2 |
|  2 | fiction    |           2 |
|  3 | irish      |           0 |
|  4 | dystopia   |           1 |
|  5 | literature |           0 |
+----+------------+-------------+

I’ve read two classics, two works of fiction, and one about dystopia. Doesn’t that seem like a lot?

What if we want to go a step further? Let’s add authors:

authors:

+----+---------------------+
| id | name                |
+----+---------------------+
|  1 | James Joyce         |
|  2 | F. Scott Fitzgerald |
|  3 | Vladimir Nabokov    |
|  4 | Aldous Huxley       |
+----+---------------------+

authors_books:

+-----------+---------+
| author_id | book_id |
+-----------+---------+
|         1 |       1 |
|         2 |       2 |
|         1 |       3 |
|         3 |       4 |
|         4 |       5 |
+-----------+---------+

If we want to do a standard inner join against the authors table (we don’t want books without authors, but we still want tags without books) we can do so with:

SELECT t.*, COUNT(b.id)
FROM tags t LEFT JOIN books_tags bt ON t.id = bt.tag_id
LEFT JOIN (books b, authors_books ab, authors a) ON b.id = bt.book_id AND b.id = ab.book_id AND ab.author_id = a.id AND a.name = ‘F. Scott Fitzgerald’ AND b.is_unread = 0
WHERE 1
GROUP BY t.id;



Selecting MySQL Rows Into Columns


Sometimes it’s nice to combine multiple database queries into one to save on round-trips, or for any other reason fetch results from separate tables in a single query without actually joining each of the tables involved. This can be done by effectively selecting the results from the rows of one query into the columns of another.

First, an example table setup; let’s say we’re collecting videos and screenshots for various websites:


CREATE TABLE IF NOT EXISTS `screenshots` (
`id` int(11) NOT NULL,
`site_id` int(11) NOT NULL,
`title` varchar(255) NOT NULL
);

INSERT INTO `screenshots` (`id`, `site_id`, `title`) VALUES(1, 1, 'Homepage');
INSERT INTO `screenshots` (`id`, `site_id`, `title`) VALUES(2, 2, 'Homepage');
INSERT INTO `screenshots` (`id`, `site_id`, `title`) VALUES(3, 1, 'Search Results');

-- --------------------------------------------------------

CREATE TABLE IF NOT EXISTS `sites` (
`id` int(11) NOT NULL,
`url` varchar(255) NOT NULL
);

INSERT INTO `sites` (`id`, `url`) VALUES(1, 'http://google.com/');
INSERT INTO `sites` (`id`, `url`) VALUES(2, 'http://yahoo.com/');

-- --------------------------------------------------------

CREATE TABLE IF NOT EXISTS `videos` (
`id` int(11) NOT NULL,
`site_id` int(11) NOT NULL,
`duration` int(11) NOT NULL
);

INSERT INTO `videos` (`id`, `site_id`, `duration`) VALUES(1, 1, 532);
INSERT INTO `videos` (`id`, `site_id`, `duration`) VALUES(1, 2, 331);

And now, the magic query, which selects the number of screenshots and the number of videos for a single site in a single query:


select
max(if(type='screenshots',num,'')) as num_screenshots,
max(if(type='videos',num,'')) as num_videos
from (
(select count(s.id) as num, 'screenshots' as type from screenshots s where s.site_id = 1)
UNION ALL
(select count(v.id) as num, 'videos' as type from videos v where v.site_id = 1)
) as foo

If you want this information for, say, all sites, we could say:


select
site_id,
max(if(type='screenshots',num,'')) as num_screenshots,
max(if(type='videos',num,'')) as num_videos
from (
(select s.site_id, count(s.id) as num, 'screenshots' as type from screenshots s where s.site_id in (1,2,3) group by site_id)
UNION ALL
(select v.site_id, count(v.id) as num, 'videos' as type from videos v where v.site_id in (1,2,3) group by site_id)
) as foo group by site_id

In Oracle something similar can be achieved using the decode or case operators.



Ruby on Rails Method Caching


While investigating caching techniques for Ruby on Rails I found the most promising to be cachesrb, which allows controller method-level caching.

I found it from this from the Rails Caching post by Robert R Evans. Rails page- and action-level caching are often too restrictive, as they don’t work well with things like query parameters or pages requiring a flash. Fragment caching is too low-level, requiring a high degree of manual intervention to be used effectively. Method caching seems to be just what we need.

It looks like the project was once active at RubyForge and is maybe now active at githug.

The wiki for the project, once available at http://pad.verbdev.com/cachesrb/, now loads only a blank page. Google Cache revels it once contained this content:


Caches.rb

Caches.rb is a simple Ruby library that allows you to let some class methods be cached.

Please note that this documentation is not double checked yet

Ongoing changes

http://rashkovskii.com/articles/2007/2/28/new-experimental-caches-rb

http://rashkovskii.com/articles/2007/4/1/ongoing-improvements-in-caches-rb

Don’t tell, show me!

OK.

Let’s assume you have an expensive method, and you want to cache it for one minute (default timeout):


def expensive_method
...
end
caches :expensive_method

When you will call your expensive method first time, it will be executed. For the next 60 seconds any call to this method will return cached value.

Want to invalidate it earlier? No problem:


...some code...
invalidate_expensive_method_cache
..some code..

Got an idea? We could move further.

Not satisfied with default timeout?


caches :expensive_method, :timeout => 10.minutes

Want to cache an accessor’s value?

Caches.rb is for you. It automatically caches getter’s value and invalidates cache on writer invocation. No extra configuration required.

Expensive method has arguments?

No problem. Caches.rb caches invocations with arguments. So, if you have


def expensive_method(arg)
...
end

then Caches.rb will cache expensive_method(1) and expensive_method(2) separately. To invalidate cache for (1), just invalidate_expensive_method_cache(1). To invalidate all expensive_method caches, just invalidate_all_expensive_method_caches. Simple? Yes!

Other

Want to invalidate all caches within a class? invalidate_all_caches is for you.

Also you can invalidate caches with except some caches


invalidate_all_caches :except => :name

or


invalidate_all_caches :except => [:name, :name1]

Revised about 1 year ago by yrashk



Virtuialization with VMware


Download VMWare Server for Linux here. You can get serial numbers here.

Unpack the download and run sudo ./vmware-install.pl. You should be fine accepting all the default settings.

If your install fails, and you can’t reinstall because “A previous installation of VMware software has been detected”, simply mv /etc/vmware /var/tmp/trash and try again.

Start the server by just saying vmware.

Download ready-to-run virtual machines here, or pop a standard OS install CD and create a new virtual machine. When the VM boots it will read from the CD and install as normal. You can also direct your VM to boot from an ISO.

When your VM is set up you’ll see a little warning at the bottom: “You do not have VMWare Tools installed.” You want VMWare tools; they make your guest machine run smoother. Under the “VM” menu choose “Install VMWare tools…” to be guided through the installation process.

« Previous PageNext Page »

powered by WordPress     themed by Mukkamu     presented by ideaharbor.org     everything else by steve hulet