Tuesday, January 25, 2011
Freediving in the Philippines. Day 1
Looking at the map, I find it hard to believe that the Philippines are so far from Australia. Indeed, if there were direct flights from Australia, it would not be so far away. But, unfortunately, none of the airlines have direct flights from Melbourne to Cebu Island of the Philippines where I was going. Therefore I had to fly to Singapore first (seven hours) and from Singapore to the Philippines (four more hours). That was certainly closer than from Moscow, but still a long way. However, I should not complain. By Australian standards it is practically around the corner. I bought the tickets so that I would meet the team of Russian freedivers midway – at the Singapore airport – and then we would fly to the Philippines on the same plane. The seven-hour flight from Melbourne to Singapore was quite easy, except for the flight being delayed for an hour, and I managed to sleep almost through. Interestingly, despite the night flight (the departure from Melbourne was at 1 a.m.), the Singaporeans offered a supper immediately after take-off and climb – at 3 o'clock in the morning. I wisely declined the "supper".
Friday, August 27, 2010
Coming Revolution

In my student days I was an avid gamer and has played virtually all "big" games that came out for PC, luckily for me those days it wasn't such a flood as now. And I remember well the events that changed the game industry as we knew it. Those milestones were:
- Doom - the first popular first-person shooter, 1993;
- 3dfx Voodoo - the first 3D accelerator, 1996;
- Nvidia GeForce 256 - the first 3D accelerator with integrated
geometry GPU, 1999.
Kinect is a small box connected to the Xbox 360. It has 2 cameras that watch the player, detect the position of his body and movement, and thereby enable you to control events on the screen. Motion Control in a pure form – simple and brilliant. No controllers, no wires. According to Microsoft's statements, one Kinect can completely digitise movements of two players and track the positions of four more. The players may be standing or sitting. In addition, Kinect has multi-array microphone through which it can recognise the voice of his "master" and obey his orders.
Microsoft presented Kinect a year ago at E3 exhibition, then it carried the working title "Project Natal". And immediately it was clear that it would be a revolution, if only Microsoft would be able to deliver on promises. Now, when Kinect is very close to the release, Microsoft has distributed sample devices to leading gaming magazines. And now we can say firmly - Microsoft succeeded. According to the lucky ones who played with Kinect, watching first time the character on the screen waiving its hands in coordination with you movements is fascinating. Motion Control is not perfect, but still very good.
This is what a gameplay with Kinect looks like:
I predict that Kinect will be a huge hit. It along with the new Xbox 360 will take the market by storm. Potential customers will have to stand in a queue for hours to buy it. And for some time after launch it will not be possible just to walk into a store and buy one, as it is now impossible to buy an iPhone 4. Neither Sony, nor Nintendo has anything comparable.
So, we are on the eve of the revolution. Now it is the turn of gaming companies to help us fully explore this bright new world.
Friday, November 6, 2009
Don't mess with LIKE
Oh boy, It looks like it's time to change the title of this blog to "A hundred ways you can screw up with Oracle". I may need a new domain name, something flashy. www.oraclewtf.com would be fine. Let me see, it is currently available. I wonder how fast cyber-squatters will jump in and snatch it now when I pronounced it. Then they will blackmail me demanding a outrageous ransom or else... (insert evil face here)
On second thought, no. I don't want to turn this blog into an Oracle-specific. There are already enough Oracle blogs out there. In fact, I think there are more of them than Oracle professionals who would read them. I don't want to bring yet another one to the world just for the sake of it. Heck, it's my place and I'm going to write about whatever I want. Hence the title, Random Thoughts.
Ok, kids, take your places. Today's lesson is (surprise, surprise!) about Oracle. We already discussed a few ways we can screw up with dates. Today we will talk about numbers. On the surface numbers look like pretty innocent data type. But once you dive a little deeper... Beware! Fearful creatures lurk beneath. And if you are not careful, they will snatch you in no time.
Take a look at this Stackoverflow.com
question by James
Collins.
James had a problem, the following query was slow:
SELECT a1.*
FROM people a1
WHERE a1.ID LIKE '119%'
AND ROWNUM < 5
Despite column A1.ID was indexed, the index wasn't used and the explain plan looked like this:
SELECT STATEMENT ALL_ROWS
Cost: 67 Bytes: 2,592 Cardinality: 4 2 COUNT STOPKEY 1 TABLE ACCESS FULL TABLE people
Cost: 67 Bytes: 3,240 Cardinality: 5
James was wondering why. Well, the key to the issue lies, as it often happens with Oracle, in an implicit data type conversion. Because Oracle is capable to perform automatic data conversions in certain cases, it sometimes does that without you knowing. And as a result, performance may suffer or code may behave not exactly like you expect.
In our case that happened because ID column was NUMBER. You see, LIKE pattern-matching condition expects to see character types as both left-hand and right-hand operands. When it encounters a NUMBER, it implicitly converts it to VARCHAR2. Hence, that query was basically silently rewritten to this:
SELECT a1.*
FROM people a1
WHERE To_char(a1.ID) LIKE '119%'
AND ROWNUM < 5
That was bad for 2 reasons:
- The conversion was executed for every row, which was slow;
- Because of a function (though implicit) in a WHERE predicate, Oracle was unable to use the index on A1.ID column.
- Create a function-based
index on A1.ID column:
CREATE INDEX people_idx5 ON people (To_char(ID));
- If you need to match records on first 3 characters of ID column, create another column of type NUMBER containing just these 3 characters and use a plain = operator on it.
- Create a separate column ID_CHAR of type VARCHAR2 and fill it with TO_CHAR(id). Index it and use instead of ID in your WHERE condition.
-
Or, as David Aldridge pointed out: "It might also be possible to rewrite the predicate as ID BETWEEN 1190000 and 1199999, if the values are all of the same order of magnitude. Or if they're not then ID = 119 OR ID BETWEEN 1190 and 1199 etc.."
Of course if you choose to create an additional column based on existing ID column, you need to keep those 2 synchronized. You can do that in batch as a single UPDATE, or in an ON-UPDATE trigger, or add that column to the appropriate INSERT and UPDATE statements in your code.
James choose to create a function-based index and it worked like a charm.
Wednesday, November 4, 2009
SYSDATE confusions
SYSDATE is one of the most commonly used Oracle functions. Indeed, whenever you need the current date or time, you just type SYSDATE and you're done. However, sometimes it's not all that simple. There are a few confusions associated with SYSDATE that are pretty common and, if not understood, can cause a lot of damage.
First of all, SYSDATE returns not just current date, but date and time combined. More precisely, the current date and time down to a second. If just a date is needed, TRUNC function has to be applied, that is, TRUNC(SYSDATE). For a sake of a good database design, date should not be confused with date/time. For example, if a column in a table is called “transaction_date”, it would be natural for it to contain a date, but not date/time. That may lead to a major confusion. Let's imagine there is a table BANK_TRANSACTIONS containing the following fields:
txn_no INTEGER, txn_amount NUMBER(14,2), txn_date DATEThe last field is of the most interest to us. Apparently its data type is “DATE”, but is it a date or date/time? We can't tell by just looking at the table definition. Nonetheless, it is a very important thing to know. A common case for using DATE columns is including them in date range queries. Forexample, if we wanted to get all the bank transactions from 1 January 2009 to 31 July 2009 we could write this:
SELECT txn_no, txn_amount FROM bank_transactions WHERE txn_date BETWEEN To_date('01-JAN-2009','DD-MON-YYYY') AND To_date('31-JUL-2009','DD-MON-YYYY')And that would be fine if TXN_DATE were a date column. But if it is a date/time, we would just have missed a whole day worth of data. And it is because, as I said, DATE data type can hold date/time down to a second. That means that for 31 July 2009 it could hold values ranging from 0:00am to 11:59pm. But because TO_DATE('31-JUL-2009', 'DD-MON-YYYY') is basically an equivalent to TO_DATE('31-JUL-2009 00:00:00', 'DD-MON-YYYY HH24:MI:SS'), all the transactions happened after 0:00am on 31 July 2009 would be missed out.
That kind of mistake is pretty common. Sometimes it's hard to tell by just looking at the data whether a particular DATE column can have date portion. Even if all the values in there are rounded to 0:00 hours, that doesn't mean that a different time value can't appear there in the future. The data dictionary can't help us here either – DATE type is always the same whether it contains time or not. (By the way, Oracle recommends using TIMESTAMP type for new projects, but that is a whole different story.)
If you are working with an existing table and you are not sure, you can use a fool-proof method like this:
SELECT txn_no, txn_amount FROM bank_transactions WHERE txn_date BETWEEN To_date('01-JAN-2009','DD-MON-YYYY') AND To_date('31-JUL-2009','DD-MON-YYYY') + 1 – 1/24/3600“+1 – 1/24/3600” here means “Plus 1 day minus 1 second”. That is because “1” in DATE type means “1 day”, “1/24” - 1 hour, and there are 3600 seconds in an hour.
The above expression will retrieve all the transactions from “01 January 2009 0:00am” to “31 July 2009 0:00am plus 1 day minus 1 second”, i.e. to “31 July 2009 23:59pm”.
If you are charged with designing an application and need to create a table with a DATE column, it is worth to keep yourself and others from future confusions by a simple trick: name columns that only contain date portions as “_DATE” and add “_TIME” to the name of the columns that you know will contain time components. In our case it would be prudent to call the date/time column TXN_DATE_TIME.
The second issue I'd like to discuss is much more subtle, but can do even more damage.
Imagine that you are charged with developing a report that returns all the transaction for the previous month. It looks like a job for SYSDATE! You fetch your trusty keyboard and after a few minutes of typing you come up with something like this:
SELECT txn_no, txn_amount FROM bank_transactions WHERE txn_date BETWEEN Last_day(Add_months(Trunc(SYSDATE),-2)) + 1 AND Last_day(Add_months(Trunc(SYSDATE),-1))You create a few lines in BANK_TRANSACTIONS table, run a few unit tests to make sure your code works and check it into the source control. Job done! You congratulate yourself on the productive work and spend the rest of the day reading your friends' blogs and dreaming about your next vacation. And the next day you move on to another task and get as busy as ever.
After some time, which may be a few days or months, depending on the pace of the project, the code you wrote gets migrated into the UAT environment. And a task force of a few testers and end users is assigned to test the report you wrote. And as it often happens in UAT, they are going to test in on real data they extracted from the production system – that is, the last year's data.
Got it? Last year's.
The final stages of testing, such as UAT, have to prove that the system does what it is expected to do in conditions that resemble the production as closely as possible. And the best way to do that is to test it on the retrospective production data – the data that is proven. That makes it possible to compare the outcome to the actual production system, and thus, prove or disprove that the new system works.
That sounds reasonable. But one of the implications for you is that BANK_TRANSACTIONS table is not going to contain previous month's transactions. Hence, your report will be blank. You can't rewind back time because you hard-coded SYSDATE, which has only one meaning – “right now”. Test failed.
If you have known that when you wrote it, you wouldn't have used the SYSDATE. You would use a parameter, something like v_run_date, which you could set to whatever date you wanted. And that would do. Well, now you know.
Friday, October 2, 2009
Make it beautiful
Wednesday, September 9, 2009
Quest for the perfect reader is almost over
Sunday, July 26, 2009
How to get a root password
- No less than in 2 weeks before day "D" create a change docket in a change management system.
- Fill a couple of 15-pages documents, describing in details what we need to do, why and how.
- Obtain approvals from our and their management.
- Obtain sign-offs from the downstream systems, even the ones that would not be affected.
- Attach all the approvals to the change docket.
- Create a task to issue a temporary root password to us.
- Send a request to the service delivery manager, asking to approve the task and assign in to a responsible person.
- Attend the Change Review Board and get the change approved.
- Find out that the task assigned to a wrong group. Reassign.
- Find out that in order to get a root password you need to fill a form.
- Obtain the form from a Security group.
- Fill the form.
- Get the form signed by 3 different people in 3 different buildings.
- Submit the form.
- In a few days get a reply from the Security group, telling that the form was filled incorrectly - a tick was put into a different box.
- Fill the form again.
- Get the form signed by 3 different people in 3 different buildings.
- Submit the form.
- After a few day's silence, start nagging the Service Delivery Manager.
- Find out that another Security group is responsible for granting root passwords.
- Reassign the task to the new group and forward the form to them.
- After a few day's silence, start nagging the Service Delivery Manager.
- Find out that yet another User Admin Security Group is responsible for granting the root passwords.
- Reassign the task to the new group and forward the form to them.
- Find out that the submitted form is outdated. The User Admin Security Group no longer accepts outdated forms. (The form that those guys themselves sent 3 weeks ago was outdated).
- Download the new form. The difference with the old one is just that the checkboxes are positioned differently.
- Fill the form again.
- Get the form signed.
- Submit the form.
- Find out that the form hasn't changed for the last 4 years.
Popular Posts
-
If you ever wanted to know how what's taking space in an Oracle database, or how large is the table you're working on, here's a...
-
A few days ago I installed Oracle Linux in an Oracle VirtualBox VM. Once it was installed I found that eth0 interface wasn't starting up...
-
I recently switched to Oracle SQL Developer for my PL/SQL development needs. I have mixed feeling about SQL Developer: it's been in dev...
-
In March 2010 I went to Cebu Island of the Philippines with a group of Russian freedivers. This is my diary of what happened there. It is a ...
-
The Composing and Producing Electronic Music course is finally over. I learned a lot over the past 12 weeks on topics like sound design, h...
-
This tutorial explains how to record the output of one MIDI track (for example, arpeggiator’s output) into another MIDI track. Although FL...
-
The next day, having arrived at Club Serena at 8 am, I discovered that the yoga had already started. I asked, and it turned out it started a...
-
It's been quite some time since I wrote these lines. And, perhaps, if I were writing this now, I wouldn't write it in the same way -...
-
The assigmnent for week 2 of Composing and Producing Electronic Music was to make a drum groove for a Drum'n Bass track. Here...
-
All database applications can be divided into 2 classes: OLTP and data warehouses. OLTP stands for Online Transactions Processing. It’s ...
