Re: locked non-existent row

2011-09-01 Thread Rik Wasmus | GRIB
On Wednesday 31 August 2011 16:39:52 Peter Brawley wrote:
  While a transaction in one thread tries to update a non-existent InnoDB
  row with a given key value, an attempt to insert that value in another
  thread is locked out. Does anyone know where this behaviour is
  documented?
  
  -- connection 1
  drop table if exists t;
  create table t( lockid char(3), lockinfo char(8), primary
  key(lockid,lockinfo) );
  insert into t values('abc','def');
  begin work;
  update t set lockinfo='bar' where lockid='foo';
  
  -- connection 2:
  insert into t values('aaa','bbb');
  Query OK, 1 row affected (0.00 sec)
  insert into t values('foo','bar'); -- waits for connection 1 transaction
  
  It has to do with transaction isolation levels. I assume REPEATABLE READ
  by default for InnoDB:
  
  http://dev.mysql.com/doc/refman/5.0/en/set-
  transaction.html#isolevel_repeatable-read
  
   For locking reads (SELECT with FOR UPDATE or LOCK IN SHARE MODE),
  UPDATE, and DELETE statements, locking depends on whether the statement
  uses a unique index with a unique search condition, or a range-type
  search condition. For a unique index with a unique search condition,
  InnoDB locks only the index record found, not the gap before it. For
  other search conditions, InnoDB locks the index range scanned, using gap
  locks or next-key (gap plus index-record) locks to block insertions by
  other sessions into the gaps covered by the range.
 
 Yes, that's what the question is about, it says for a unique key value,
 as in this case, it locks only the index record found. There is no
 index record. InnoDb behaves, though, as if there is one. Where is the
 documentation for that?

Is says it employs different strategies, I see it as:

(unique index with a unique search condition = InnoDB locks only the index 
record found)
 OR
(other search conditions = InnoDB locks the index range scanned, using gap 
locks or next-key )

And 'lockinfo' is most certainly in your index, a primary key is a special 
kind of UNIQUE, but still unique. The INSERT cannot complete as the 
(lockid,lockinfo) location (foo,bar) is locked, until commit or rollback. See 
the index as a seperate storage from your normale table-rows which your INSERT 
needs to put something in to complete the insert. The UPDATE has locked that 
location, so the INSERT waits for that. That's the 'index record' they're 
talking about I gather.

Also: please respond to the list only, I have enough mail as it is, responding 
to the list keeps things nicely organized :)
-- 
Rik

-- 
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:http://lists.mysql.com/mysql?unsub=arch...@jab.org



Re: Query Optimization

2011-09-01 Thread Jochem van Dieten
On Aug 30, 2011 6:46 PM, Brandon Phelps wrote:
 SELECT
sc.open_dt,
sc.close_dt,
sc.protocol,
INET_NTOA( sc.src_address ) AS src_address,
sc.src_port,
INET_NTOA( sc.dst_address ) AS dst_address,
sc.dst_port,
sc.sent,
sc.rcvd,
spm.desc AS src_port_desc,
dpm.desc AS dst_port_desc
 FROM firewall_connections AS sc

If this is a firewall connection log I presume open_dt is the time a
connection was opened and is always going to be less than close_dt. Right?

 WHERE
(open_dt = '2011-08-30 00:00:00' OR close_dt = '2011-08-30
00:00:00')
AND (open_dt = '2011-08-30 12:36:53' OR close_dt = '2011-08-30
12:36:53')

In that case your logic here simplifies to:
WHERE
  open_dt = '2011-08-30 00:00:00'
  AND
  close_dt = '2011-08-30 12:36:53'

Now add an index over open_dt and close_dt and see what happens.

Jochem


Re: Query Optimization

2011-09-01 Thread Brandon Phelps

On 09/01/2011 04:59 AM, Jochem van Dieten wrote:
  SELECT
 sc.open_dt,
 sc.close_dt,
 sc.protocol,
 INET_NTOA( sc.src_address ) AS src_address,
 sc.src_port,
 INET_NTOA( sc.dst_address ) AS dst_address,
 sc.dst_port,
 sc.sent,
 sc.rcvd,
 spm.desc AS src_port_desc,
 dpm.desc AS dst_port_desc
  FROM firewall_connections AS sc

 If this is a firewall connection log I presume open_dt is the time a
 connection was opened and is always going to be less than close_dt.
 Right?

  WHERE
 (open_dt = '2011-08-30 00:00:00' OR close_dt = '2011-08-30
00:00:00')
 AND (open_dt = '2011-08-30 12:36:53' OR close_dt = 
'2011-08-30 12:36:53')


 In that case your logic here simplifies to:
 WHERE
   open_dt = '2011-08-30 00:00:00'
   AND
   close_dt = '2011-08-30 12:36:53'

 Now add an index over open_dt and close_dt and see what happens.

 Jochem

Jochem,

I can't really use your WHERE logic because I also need to retrieve 
results where the open_dt time is out of the range specified.  For 
example, a very large file download might span multiple days so given 
your logic if the connection was started 2 days ago and I want to pull 1 
days worth of connections, I would miss that entry.  Basically I want to 
SELECT all of the records that were opened OR closed during the 
specified time period, ie. if any activity happened between my start and 
end dates, I need to see that record.


Any other ideas?

Thanks again,
Brandon

--
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:http://lists.mysql.com/mysql?unsub=arch...@jab.org



RE: locked non-existent row

2011-09-01 Thread Jerry Schwartz
-Original Message-
From: Peter Brawley [mailto:peter.braw...@earthlink.net]
Sent: Wednesday, August 31, 2011 10:40 AM
To: r...@grib.nl; mysql@lists.mysql.com
Subject: Re: locked non-existent row

On 8/31/2011 4:50 AM, Rik Wasmus wrote:
 While a transaction in one thread tries to update a non-existent InnoDB
 row with a given key value, an attempt to insert that value in another
 thread is locked out. Does anyone know where this behaviour is documented?

[JS] Forgive my ignorance, but I thought that was standard behavior for a row- 
or row-range lock (not just MySQL) in any DBMS that supported row locking. 
(Back when these things were first being invented, one term was predicate 
locking.) The general idea was that you are locking rows that meet certain 
criteria, whether any or all of them exist or not. You're locking not only the 
existence, but the potential existence, of those rows.

I would expect it to apply not only to keys, but to any set. For example,

SELECT * FROM `t` WHERE `t`.`x`  3 FOR UPDATE;

should lock all rows where `t`.`x`  3 for update, insertion, or deletion --  
regardless of whether or not `x` is a key. Otherwise you have no way of 
knowing who wins.

The ability to lock non-existent records is critical.

Try it, you'll see.


Regards,

Jerry Schwartz
Global Information Incorporated
195 Farmington Ave.
Farmington, CT 06032

860.674.8796 / FAX: 860.674.8341
E-mail: je...@gii.co.jp
Web site: www.giiresearch.com







-- 
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:http://lists.mysql.com/mysql?unsub=arch...@jab.org



Re: locked non-existent row

2011-09-01 Thread Rik Wasmus
 -Original Message-
 From: Peter Brawley [mailto:peter.braw...@earthlink.net]
 Sent: Wednesday, August 31, 2011 10:40 AM
 To: r...@grib.nl; mysql@lists.mysql.com
 Subject: Re: locked non-existent row
 
 On 8/31/2011 4:50 AM, Rik Wasmus wrote:
  While a transaction in one thread tries to update a non-existent InnoDB
  row with a given key value, an attempt to insert that value in another
  thread is locked out. Does anyone know where this behaviour is
  documented?
 
 [JS] Forgive my ignorance, but I thought that was standard behavior for a
 row- or row-range lock (not just MySQL) in any DBMS that supported row
 locking. (Back when these things were first being invented, one term was
 predicate locking.) The general idea was that you are locking rows that
 meet certain criteria, whether any or all of them exist or not. You're
 locking not only the existence, but the potential existence, of those
 rows.
 
 I would expect it to apply not only to keys, but to any set. For example,
 
 SELECT * FROM `t` WHERE `t`.`x`  3 FOR UPDATE;
 
 should lock all rows where `t`.`x`  3 for update, insertion, or deletion
 -- regardless of whether or not `x` is a key. Otherwise you have no way of
 knowing who wins.
 
 The ability to lock non-existent records is critical.

I concur, although this is just a transaction consisting of 1 statement :).
-- 
Rik Wasmus

-- 
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:http://lists.mysql.com/mysql?unsub=arch...@jab.org



Re: locked non-existent row

2011-09-01 Thread Peter Brawley

On 9/1/2011 9:46 AM, Rik Wasmus wrote:

-Original Message-
From: Peter Brawley [mailto:peter.braw...@earthlink.net]
Sent: Wednesday, August 31, 2011 10:40 AM
To: r...@grib.nl; mysql@lists.mysql.com
Subject: Re: locked non-existent row

On 8/31/2011 4:50 AM, Rik Wasmus wrote:

While a transaction in one thread tries to update a non-existent InnoDB
row with a given key value, an attempt to insert that value in another
thread is locked out. Does anyone know where this behaviour is
documented?

[JS] Forgive my ignorance, but I thought that was standard behavior for a
row- or row-range lock (not just MySQL) in any DBMS that supported row
locking. (Back when these things were first being invented, one term was
predicate locking.) The general idea was that you are locking rows that
meet certain criteria, whether any or all of them exist or not. You're
locking not only the existence, but the potential existence, of those
rows.

I would expect it to apply not only to keys, but to any set. For example,

SELECT * FROM `t` WHERE `t`.`x`  3 FOR UPDATE;

should lock all rows where `t`.`x`  3 for update, insertion, or deletion
-- regardless of whether or not `x` is a key. Otherwise you have no way of
knowing who wins.

The ability to lock non-existent records is critical.
Yes, though I'm told that SQL Server, for example, does not do this 
(I've not confirmed that myself). The question here is whether the cited 
docs para adequately describes what InnoDB is doing, ie treating a 
single non-existent key value as a range.


PB

-


I concur, although this is just a transaction consisting of 1 statement :).


--
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:http://lists.mysql.com/mysql?unsub=arch...@jab.org



Re: Query Optimization

2011-09-01 Thread Shawn Green (MySQL)

On 9/1/2011 09:42, Brandon Phelps wrote:

On 09/01/2011 04:59 AM, Jochem van Dieten wrote:
   ...

   WHERE
   (open_dt = '2011-08-30 00:00:00' OR close_dt = '2011-08-30
00:00:00')
   AND (open_dt = '2011-08-30 12:36:53' OR close_dt = '2011-08-30
12:36:53')

  In that case your logic here simplifies to:
  WHERE
  open_dt = '2011-08-30 00:00:00'
  AND
  close_dt = '2011-08-30 12:36:53'

  Now add an index over open_dt and close_dt and see what happens.

  Jochem

Jochem,

I can't really use your WHERE logic because I also need to retrieve
results where the open_dt time is out of the range specified. For
example, a very large file download might span multiple days so given
your logic if the connection was started 2 days ago and I want to pull 1
days worth of connections, I would miss that entry. Basically I want to
SELECT all of the records that were opened OR closed during the
specified time period, ie. if any activity happened between my start and
end dates, I need to see that record.

Any other ideas?



I believe Jochem was on the right track but he got his dates reversed.

Let's try a little ASCII art to show the situation. I will setup a query 
window with two markers (s) and (e).  Events will be marked by || 
markers showing their durations.


a)   (s)   (e)
b) |---|
c)  |---|
d)|---|
e)  ||
f) |---|
g) |---|

To describe these situations:
a) is the window for which you want to query (s) is the starting time 
and (e) is the ending time for the date range you are interested in.
b) the event starts and stops before your window exists. It won't be 
part of your results.
c) the event starts before the window but ends within the window - 
include this

d) the event starts and ends within the window  - include this
e) the event starts before the window and ends after the window - 
include this
f) the event starts inside the window but ends beyond the window - 
include this.

g) the event starts and ends beyond the window - exclude this.

In order to get every event in the range of c-f, here is what you need 
for a WHERE clause


WHERE start = (ending time) and end = (starting time)

Try that and let us know the results.
--
Shawn Green
MySQL Principal Technical Support Engineer
Oracle USA, Inc. - Hardware and Software, Engineered to Work Together.
Office: Blountville, TN

--
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:http://lists.mysql.com/mysql?unsub=arch...@jab.org



Re: Query Optimization

2011-09-01 Thread Brandon Phelps

On 09/01/2011 12:47 PM, Shawn Green (MySQL) wrote:

On 9/1/2011 09:42, Brandon Phelps wrote:

On 09/01/2011 04:59 AM, Jochem van Dieten wrote:
  ...

  WHERE
  (open_dt = '2011-08-30 00:00:00' OR close_dt = '2011-08-30
00:00:00')
  AND (open_dt = '2011-08-30 12:36:53' OR close_dt = '2011-08-30
12:36:53')

 In that case your logic here simplifies to:
 WHERE
 open_dt = '2011-08-30 00:00:00'
 AND
 close_dt = '2011-08-30 12:36:53'

 Now add an index over open_dt and close_dt and see what happens.

 Jochem

Jochem,

I can't really use your WHERE logic because I also need to retrieve
results where the open_dt time is out of the range specified. For
example, a very large file download might span multiple days so given
your logic if the connection was started 2 days ago and I want to pull 1
days worth of connections, I would miss that entry. Basically I want to
SELECT all of the records that were opened OR closed during the
specified time period, ie. if any activity happened between my start and
end dates, I need to see that record.

Any other ideas?



I believe Jochem was on the right track but he got his dates reversed.

Let's try a little ASCII art to show the situation. I will setup a query window 
with two markers (s) and (e). Events will be marked by || markers showing 
their durations.

a) (s) (e)
b) |---|
c) |---|
d) |---|
e) ||
f) |---|
g) |---|

To describe these situations:
a) is the window for which you want to query (s) is the starting time and (e) 
is the ending time for the date range you are interested in.
b) the event starts and stops before your window exists. It won't be part of 
your results.
c) the event starts before the window but ends within the window - include this
d) the event starts and ends within the window - include this
e) the event starts before the window and ends after the window - include this
f) the event starts inside the window but ends beyond the window - include this.
g) the event starts and ends beyond the window - exclude this.

In order to get every event in the range of c-f, here is what you need for a 
WHERE clause

WHERE start = (ending time) and end = (starting time)

Try that and let us know the results.


Thanks Jochem and Shawn, however the following two queries result in the exact 
same EXPLAIN output:   (I hope the tables don't wrap too early for you)

Old method:
SELECT
sc.open_dt,
sc.close_dt,
sc.protocol,
INET_NTOA(sc.src_address) AS src_address,
sc.src_port,
INET_NTOA(sc.dst_address) AS dst_address,
sc.dst_port,
sc.sent,
sc.rcvd,
spm.desc AS src_port_desc,
dpm.desc AS dst_port_desc
FROM firewall_connections AS sc
LEFT JOIN port_mappings AS spm ON spm.port = sc.src_port
LEFT JOIN port_mappings AS dpm ON dpm.port = sc.dst_port
WHERE
(open_dt = '2011-08-31 09:53:31' OR close_dt = '2011-08-31 09:53:31')
AND (open_dt = '2011-09-01 09:53:31' OR close_dt = '2011-09-01 
09:53:31')
ORDER BY rcvd DESC
LIMIT 0, 10;

New method with BTREE index on open_dt, close_dt (index name is 
ndx_open_close_dt):
SELECT
sc.open_dt,
sc.close_dt,
sc.protocol,
INET_NTOA(sc.src_address) AS src_address,
sc.src_port,
INET_NTOA(sc.dst_address) AS dst_address,
sc.dst_port,
sc.sent,
sc.rcvd,
spm.desc AS src_port_desc,
dpm.desc AS dst_port_desc
FROM firewall_connections AS sc
LEFT JOIN port_mappings AS spm ON spm.port = sc.src_port
LEFT JOIN port_mappings AS dpm ON dpm.port = sc.dst_port
WHERE
open_dt = '2011-09-01 09:53:31' AND close_dt = '2011-08-31 09:53:31'
ORDER BY rcvd DESC
LIMIT 0, 10;

EXPLAIN output for old method:
++-+---++---+--+-++--+-+
| id | select_type | table | type   | possible_keys | key  | 
key_len | ref| rows | Extra   |
++-+---++---+--+-++--+-+
|  1 | SIMPLE  | sc| index  | open_dt,ndx_open_close_dt | ndx_rcvd | 4  
 | NULL   |   10 | Using where |
|  1 | SIMPLE  | spm   | eq_ref | PRIMARY   | PRIMARY  | 2  
 | syslog.sc.src_port |1 | |
|  1 | SIMPLE  | dpm   | eq_ref | PRIMARY   | PRIMARY  | 2  
 | syslog.sc.dst_port |1 | |
++-+---++---+--+-++--+-+

EXPLAIN output for new method with new index:
++-+---++---+--+-++--+-+
| id | select_type | table | type   | possible_keys | key  | 
key_len | ref| rows | Extra   |

RE: locked non-existent row

2011-09-01 Thread Jerry Schwartz
 The ability to lock non-existent records is critical.

I concur, although this is just a transaction consisting of 1 statement :).
--
[JS] As the Three Musketeers used to say, One for all and all for one!

Peter, I couldn't even //understand// that paragraph about key gaps. The 
document writers might have assumed that this aspect of locking was universal 
and well known, and didn't think it needed explanation.

As for MS SQL Server, I would be dumbfounded if it worked differently; but 
I've been dumbfounded before by software design.

My standard answer for Why does it work that way? is I am not a mental 
health professional, nor do I play one on TV.

Regards,

Jerry Schwartz
Global Information Incorporated
195 Farmington Ave.
Farmington, CT 06032

860.674.8796 / FAX: 860.674.8341
E-mail: je...@gii.co.jp
Web site: www.giiresearch.com







-- 
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:http://lists.mysql.com/mysql?unsub=arch...@jab.org