I haven’t uploaded many photos lately, so I figured I’d shoot one of my car:

What? What? It’s in the picture.
Yes, mine would be the bumper car on the far left. One of these days….
I haven’t uploaded many photos lately, so I figured I’d shoot one of my car:

What? What? It’s in the picture.
Yes, mine would be the bumper car on the far left. One of these days….
I’m a big fan of the relatively inexpensive Case Studio as an alternative to the big database design tools. Case Studio does a very competent job at reverse engineering databases, modeling, UML, etc.
The reverse engineering just got a whole lot better with the recent InferRI add-in that can infer relationships between tables even when no relationship is defined in the database. It looks at what fields are the primary keys in each table, and then looks for similarly named fields in other tables. This makes reverse-engineering databases a lot easier for database administrators who don’t like to force the database to enforce relationships, or who take over databases that have never been managed by a DBA before. This thing just saved me a couple hours of work.
The only drawback is that the field names have to be identical. If the Customer table has a primary key of CustomerID, and the Orders table has a field called PurchasingCustomerID, CaseStudio won’t infer the join between the two tables.
Pretty damn good for a first version of the add-in, though.
The latest newsletter from the excellent SQL-Server-Performance.com had a tip about doing performance tuning on high-powered machines. If you need to test large queries running inside the server room (meaning, the app or web server runs a big query against the db server), you may not get the speed results you’re expecting if you try to run that same query on your desktop. SQL-Server-Performance attributes this to low resources on the desktop, but there can also be another reason: network bandwidth and latency.
Last week, I was doing performance tuning on a SQL Server that supports users across the United States. One of the applications exhibited very high Duration numbers in the profiles that I ran, and I couldn’t figure out why. Even when I tuned the tables by adding appropriate indexes, the load on the server didn’t improve the way I’d expected. Finally, I found out that this particular application was running on machines in another state – not application servers inside our data centers like we’d typically do. The query results were being piped over their slow VPN connection down to their workstations, and so the Duration statistics were artificially high. Sure, it looked like the queries were taking forever, but in reality, it was just a slow network connection, and there was nothing I could do on the database side to speed that up.
The morale of that first story: never performance tune by looking at a single statistic alone, like Duration, Reads, Writes, or CPU. Use all of them together to gauge what queries are really having an impact.
Technorati tags: PerformanceTuning, SQLServer
.flickr-photo { border: solid 2px #000000; }
.flickr-yourcomment { }
.flickr-frame { text-align: left; padding: 3px; }
.flickr-caption { font-size: 0.8em; margin-top: 0px; }
Our coffeemaker carafe broke for the second time. I ordered a new carafe, and in the meantime, we’re making do with the Premium Roast coffee from McDonald’s down the street. It’s hard to complain when there are half a dozen coffee shops within walking distance. I love Miami Beach.
.flickr-photo { border: solid 2px #000000; }
.flickr-yourcomment { }
.flickr-frame { text-align: left; padding: 3px; }
.flickr-caption { font-size: 0.8em; margin-top: 0px; }
I’ve blogged about more of the downsides than the upsides of my new Cingular 8125, and it’s time for some opposing views.
Stuck in the datacenter working on a dead server, this thing proves its worth. I’m able to take full advantage of some spare time while waiting for stuff to work. I’ve caught up on my emails. I’ve caught up on my voicemail, thanks to our slick VoIP phones that send our voicemails to email. I’m even blogging! Hooah!
Now I just need a pair of Bluetooth headphones so I can whistle while I work.
For the past few days, I’ve complained a couple of times about the lack of testing on my new Cingular 8125. My troubles continue with the MMS integration. The device has a great digital camera, and it has great email support, but do the two work together? Not so much.
STEPS TO REPRODUCE:
1. Take a picture. (I took this particular one yesterday afternoon while walking Ernie down the boardwalk, and I’m only now getting the damn thing into my blog because this process is such a pain in the ass.)
2. Click Send at the bottom of the screen.
3. You get options for each of your email accounts – but not Goodlink, and I can almost understand that because it’s a third-party email client. However, Cingular touts its support, so Cingular should really support it. Bottom line, you can’t send camera phone attachments with Goodlink. But I digress – back to this particular bug. Choose MMS, a picture message.
4. The MMS window pops up, and the first thing is the “To” address.
5. Start typing a person’s name, an email address, or a phone number.
ACTUAL BEHAVIOR:
Nothing happens.
EXPECTED BEHAVIOR:
When I start typing an email address or a phone number, it should pick from my list of contacts and complete the address for me. Or at the very least, it should pop up a clumsy additional window and let me pick an address from my address book. No such luck. It’s as if my address book on the device didn’t even exist. Come on, man, this device fits in the palm of my hand – why are all of the parts so damned independent?
This brings me to testing. The bug reporting format I used above was copy/pasted from the Flock wiki entry on submitting Flock bugs. If I have a problem with the browser, I can simply submit a bug report like I did this morning. I caught a minor grammatical error and submitted a bug for it. I can then watch the Flock crew react to it, hopefully fix it, and publish the fixed code. I can download the fixed browser and see my contribution in action. The very fact that they’re open to my opinion gets me even more excited about using their product.
Now, contrast that with my Cingular 8125. I shudder to think at what would happen if I tried to report a bug to Cingular. I know they have to deal with a lot more users, and they have to insulate their developers better from their end users, but there should still be an open forum at some point where I can go to find problems other people are having with this device and its firmware. Oh, sure, there are forums alright, but they’re independent third-party phone forums that have sprung up out of desperation because they can’t get what they want from the big companies. But that doesn’t make me more excited about Cingular – it makes me more excited about the forums. Cingular has a chance to build their brand here, build a community of involved users, and they’re missing the boat.
Flock, on the other hand, Gets It. They understand that by building a community of involved users, they encourage their product to grow and spread wings.
I had to do some developer training last week and I wrote up a paper on the basics of primary keys and indexes. Sure, there’s tons of similar stuff around the net, but this is MINE, baby.
For our evil training purposes, let’s say we work for the phone company, and we need a database table with phone numbers. We need to track:
(Sometimes a person or a business will have multiple phone numbers, but for the sake of this training, let’s keep it a simple flat table.)
We will never have two records in here with the same phone number. We have to tell our database about that by making the phone number our primary key. When we make the phone number the primary key, we’re telling SQL Server that there can be no duplicate phone numbers.
That means every time a record is inserted or updated in this table, SQL Server has to check to make sure nobody exists with that same phone number.
As of the year 2000, there were about 360,000 people in Miami. Throw in businesses, and let’s say our table has 500,000 records in it.
That means by default, every time we insert one eensy little record, SQL Server has to read half a million records just to make sure nobody else has the same phone number!
Every 1 write = 500,000 reads.
Well, that won’t work, will it? So let’s organize our table in the order of phone number. That way, when SQL Server inserts or updates records, it can quickly jump to the exact area of that phone number and determine whether or not there’s any existing duplicates.
This is called setting up a primary CLUSTERED key. It’s called clustered because – well, I have no idea why it’s called clustered, but the bottom line is that if you could look at the actual hard drive the data was stored on, it would be stored in order of phone number.
This is different from a primary NONCLUSTERED key – nonclustered means it has nothing to do with the way the data is stored on the physical hard drive.
So to recap:
Sounds like a black and white decision, right? It usually is. There are ways to make primary nonclustered keys fast, but it needs to be a very careful decision not taken lightly, because there are a heck of a lot of ways to make them dead slow.
But let’s get back to our phone number table. Now we have the table organized by phone number, and if we want to find people by phone number, it’ll be very fast. While our computer systems will usually need to grab people’s data by phone number, our customers and end users often need to get numbers by other ways. That’s where indexes come in.
Our customers constantly need to find people’s phone numbers by their name. They don’t know the phone number, but they know the last name and first name. We would create an index called the White Pages:
That index would save people a ton of time. Think about how you use the white pages:
Now think about how you would do it without the White Pages. Think if you only had a book with 500,000 records in it, organized by phone number. You would have to scan through all 500,000 records and check the last name and first name fields.
The database works the same way, except it’s even worse! If a developer wrote a SQL query looking for the phone number, it would look like this:
SELECT PhoneNumber FROM Directory WHERE LastName = ‘Smith’ AND FirstName = ‘John’
That doesn’t say select the top one – it says select ALL of them. When you, as a human being, go through that list of 500,000 phone numbers, you would stop when you thought you found the right John Smith. The database server can’t do that – if it finds John Smith at row #15, it doesn’t matter, because there might be a few John Smiths. Whenever you do a table scan and you don’t specify how many records you need, it absolutely, positively has to scan all 500,000 records no matter what.
If the database has an index by last name and first name, though, the database server can quickly jump to Smith, John and start reading. The instant it hits Smith, Johnathan, it knows it can stop, because there’s no more John Smiths.
But that’s not always enough. Sometimes we have more than one John Smith, and the customer needs to know which John Smith to call. After all, if your name was John Smith, and the phone book didn’t include your address, you’d get pretty tired of answering the phone and saying, “No, you want the John Smith on Red Road. He’s 305-838-3333.”
So we would add the Address 1 field in there too.
Do we absolutely need the address in our index for every query? No, but we include it for convenience because when we DO need it, we need it bad. And if we DON’T need it, it doesn’t really hurt us much.
This is called a covering index because it covers other fields that are useful.
Adding the address field to our index does make it larger. A phone book without addresses would be a little thinner, and we could pack more on a page. We probably don’t want to include the Address 2 field, because the Address 1 field is enough to get what we need. The database administrator has to make judgement calls as to which fields to use on a covering index, and which ones to skip.
When building covering indexes, the covering fields go at the end of the index. Obviously, this index would suck:
We don’t want all of the Smiths ordered by their address, and then a jumbled mess of first names. That wouldn’t be as fast and easy to use. That’s why the covering fields go at the end, and the names go first – because we use those.
If you wanted to search for Brent Ozar in the phone book, you look in the O’s for Ozar first, and then you’ll find Ozar, Brent. This is more efficient than organizing the phone book by first name then last name because there are more unique last names than first names. There are probably more Brents in Miami than Ozars.
This is called selectivity. The last name field is more selective than the first name field because it has more unique values.
For lookup tables – meaning, when users need to look up a specific record – when you’ve narrowed down the list of fields that you’re going to use in an index, generally you put the most selective field first.
Indexes should almost never be set up with a non-selective field first, like Gender. Imagine a phone book organized by Gender, Last Name, First Name: it would only be useful when you wanted a complete list of all women in Miami. Not that that’s a bad thing – but no matter how much of a suave guy you think you are, you don’t really need ALL of the women in Miami. This is why non-selective indexes aren’t all that useful on lookup tables.
This rule is really important for lookup tables, but what if you aren’t trying to look up a single specific record? What if you’re interested in a range of records? Well, let’s look at…
When we need to find a dog groomer, we don’t want to go shuffling through the white pages looking for anything that sounds like a dog groomer. We want a list of organized by business category:
Then we’ll look at the list of businesses, see which name sounds the coolest and which address is closest to ours, and we’ll call a few of them. We’ll work with several of the records.
Here, we’re searching for a range of records, not just a single one.
Notice that we didn’t put the most selective field first in the index. The field “Business Name” is more selective than “Business Category”. But we put Business Name first because we need to work with a range of records.
When you’re building indexes, you not only need to know what fields are important, but you have to know how the user is fetching records. If they need several records in a row next to each other, then it may be more helpful to arrange the records like that by carefully choosing the order of the fields in the index.
When in doubt, experiment. Create two or more indexes with the same fields, but in different orders. Then check your query execution plan to see which index gets used.
When we’re dealing with a lot of data, sometimes we partition the same data into multiple tables. The phone company separates its customer list into cities, for example, so that there are separate tables for Miami and for Fort Lauderdale.
When customers want to look up a phone number, they grab the Miami phone book. They don’t want to look in the Fort Lauderdale phone book for someone who lives in Miami.
But how do they know which book to use?
They look at the front of the book, where it says “Miami, Florida”. This is a constraint: this book is constrained to Miami numbers only.
Constraints help us because it means we don’t have to put fields like State in our index. When our users are looking at a single entry in the phone book, they don’t have to wonder which State the entry is for. The book is constrained to State = ‘FL’.
Databases need constraints too. We might create a table called OrderHistory_FL, and put a State field in it. However, our poor little database doesn’t know that only FL orders are stored in this table, because the table name doesn’t mean anything. We have to specifically create a constraint on the state field.
When the database server builds query execution plans, it looks at the constraints on each table and uses that knowledge to help build a better execution plan. If it knows that it will only find states of ‘FL’ in a particular table, then it knows it doesn’t have to do any work when the query says WHERE STATE = ‘FL’. The database already knows that all records in that table match the constraint – just like if I tell you to find me all of the John Smiths in Miami, you don’t have to call each of the John Smiths in the phone book and ask them if they’re actually in Miami.
Wanna learn more? Not by now you don’t – you’ve probably had enough reading for a while, but just in case, here’s a few good pages:
Clustered Indexes and Non-Clustered Indexes
http://www.sql-server-performance.com/gv_index_data_structures.asp
http://www.sql-server-performance.com/gv_clustered_indexes.asp
http://www.sql-server-performance.com/mr_indexing.asp
Picking Good Indexes
http://www.sql-server-performance.com/indexes_not_equal.asp
http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032254503&Culture=en-US
After working with my new Cingular 8125 for a few days, I can say it’s a keeper. As soon as my memory card gets here, I’ll probably even stop carrying my laptop home during the week. I haven’t even started putting 3rd party applications on it yet, but I can say that it’s going to be my primary electronic device outside of the office.
Every single good feature, though, has the oddest drawbacks that point to insufficient testing.
Good: the keyboard buttons are huge and make typing a breeze. Bad: there are so many buttons scattered all over the damn thing that it’s almost impossible to hold without accidentally triggering the camera, voice dialing, comm manager, etc. It’s great for short-term typing, say one paragraph or less, but anything longer than that is risking disaster. It’s just too easy to accidentally start another application right in the middle of typing a paragraph, and then depending on what keys you’re in the middle of pressing, you might trigger disaster. I’ve started phone calls to people, deleted files, taken pictures, etc, all while trying to just type a letter.
Furthermore, with so many multi-purpose buttons liberally slathered all over the phone, why take up onscreen space with visual buttons that have the same purpose? There’s a dedicated hardware button for the Comm Manager – why take up an entire line of the “Today” screen to show one tiny icon for it as well? And don’t get me started about the location of the Power button: when the phone is holstered, the power button is precisely positioned to hit the seat belt socket in a car. Every time I get into the car, I turn the phone on without knowing it, and then as I buckle the seat belt, it places a call. I’m to the point now where I just take the phone off before I get in the car.
Good: two soft keys make it easy to get around in most screens, and HTC even duplicated them above the keyboard for use when the unit is in landscape mode. Bad: these two buttons are so close to the keys that they’re almost impossible to avoid. When composing email, the soft key right above the E will instantly send the email without asking if you’re sure. I looked like an idiot when I sent out three partially completed emails in a row to a group of execs. Not good. If this setup was tested, it was tested by somebody with needles for fingers.
Good: the 8125 comes with a stereo earbud headset with microphone, and it makes a killer wireless walkman. I love walking the dog while listening to Jimmy Buffett’s Radio Margaritaville over the internet, all live. Bad: the earbuds are huge. We’re talking mammoth. I don’t have small ears by any means, but I can’t keep these earbuds in my ears. They pop out at the slightest provocation because they’re apparently designed to fit in Ernie’s ears. There’s no way anybody tested these before deploying them.
Good: the camera takes great pictures for a PDA/phone. The picture you see here was taken outside at dusk with minimal lighting. The camera is very light-sensitive for a simple PDA, and a $300 PDA at that. Bad: despite buttons scattered all over the surface of this device, it’s impossible to change most of the camera settings without getting out the stylus.
Good: underground firmware available on the web enables Microsoft Direct Push email with Exchange. Companies using Exchange Server 2003 with SP2 can enable push email out to PDA’s and phones without paying for GoodLink or Blackberry Enterprise Server setups. It works pretty well out of the box with no configuration. Bad: while the push email does work, it isn’t anywhere near the speed of GoodLink or Blackberry devices. I routinely got emails on my PDA several minutes after they arrived in my inbox – not acceptable for “instant” email. Thankfully, our company uses GoodLink as well, and one of the network guys hooked me up with a GoodLink account. Presto, the emails arrived on my 8125 even before they hit my laptop. That’s what I call push email!
Good: wifi reception is better than I expected. Bad: the phone doesn’t intelligently switch over to WiFi for browsing when available. I’ve even had to manually shut off the GPRS connection just to force all communications to go over the available WiFi connection just to get the fast speed. Totally worth it, though – this device makes for a completely workable web browser from the couch during TV commercials.
Good: the device works pretty well as a phone, and the big screen means the onscreen buttons are large enough to actually work for one-handed dialing. Bad: it doesn’t come with support for A2DP, the new stereo Bluetooth profile for headsets like the droolworthy Jabra BT620. It doesn’t even come with some of the more basic features I expect in an intelligent phone, like the ability to set custom ringtones based on the caller. Come on, man, don’t let my shiny new PocketPC phone get outsmarted by a $50 Nokia.
All of the annoyances I’ve mentioned are minor. The best review comes from everybody who sees this thing in action. They all seem to say the same word: “Whoa.” The screen is big and bright, the keyboard buttons are better than a Treo’s, and it runs Windows Mobile 5. At $300 from Cingular, it’s a heck of a deal. I don’t buy new gadgets as often as I used to, and I’m completely confident in buying this thing right now. It’s the best PocketPC phone on the market today, and it’ll be a long time before anything better hits the stores at this price point.
Take two.
It’s hard to write a glowing review of a piece of consumer electronics when the damn thing crashes every half hour or so.
As I was saying when I was so rudely interrupted by a frozen screen, my new Cingular 8125 has everything from WiFi to Bluetooth to a full-blown keyboard.
Make that a half-baked keyboard. The keyboard, like the rest of this rebadged HTC Wizard, has a few annoyances that mar an otherwise amazing experience.
Take the keyboard backlighting, for example. At first, I was amazed that the keyboard lighting worked so well. After a few minutes, though, I got aggravated by how quickly the backlight turned off. The keyboard doubles up every letter key with punctuation or numbers. The only punctuation mark with its own key is the period. To use a question mark, I have to find it on the keyboard, then hit the modifier key and the key. If I don’t find it in time, the backlight cuts off, and I have to hit some random key to turn it back on, then backspace, and start looking again for my punctuation mark. Typing becomes a sort of masochistic race against the clock.
But who cares, right? I’m lounging on the couch blogging from my phone! I’m even listening to Jimmy Buffett’s Radio Margaritaville streaming audio out of this thing’s stereo speakers WHILE I TYPE! It’s a freaking multitasking phone! This little machine is way more fun than a $300 phone has a right to be. And the camera quality is spectacular. Just look at at the picture attached to this blog entry!
Oh, wait. That’s right. I can’t get the thing to email a decently sized picture because it keeps timing out trying to send an mms message. Another annoyance.
Every feature I’ve tried so far has a similar drawback. Thankfully, it looks like everything has a workaround so far. It crashes unexpectedly, so I’ve already learned to pen my blog entries in Word instead of the web browser, saving them every few minutes as I go. Like any good relationship, it’s all about compromise. You never get exactly what you want. You have to put up with a little flakiness in order to get the good stuff. So far, the Cingular 8125′s a good balance between the two.
.flickr-photo { border: solid 2px #000000; }
.flickr-yourcomment { }
.flickr-frame { text-align: left; padding: 3px; }
.flickr-caption { font-size: 0.8em; margin-top: 0px; }
I absolutely love this restaurant, but I can’t say the same for my old Sony camera phone anymore. My new Cingular 8125 is on the way!