Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
ea3ea9ed
Commit
ea3ea9ed
authored
Oct 23, 2005
by
sergefp@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
Merge spetrunia@bk-internal.mysql.com:/home/bk/mysql-4.1
into mysql.com:/home/psergey/mysql-4.1-nulls-stats-r2
parents
7510c454
e3f623d6
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
404 additions
and
38 deletions
+404
-38
include/my_base.h
include/my_base.h
+2
-0
include/my_handler.h
include/my_handler.h
+2
-0
include/myisam.h
include/myisam.h
+12
-2
myisam/mi_check.c
myisam/mi_check.c
+178
-22
myisam/myisamchk.c
myisam/myisamchk.c
+20
-4
myisam/myisamdef.h
myisam/myisamdef.h
+7
-0
myisam/sort.c
myisam/sort.c
+6
-2
mysql-test/r/myisam.result
mysql-test/r/myisam.result
+32
-0
mysql-test/t/myisam.test
mysql-test/t/myisam.test
+19
-0
mysys/my_handler.c
mysys/my_handler.c
+109
-2
sql/ha_myisam.cc
sql/ha_myisam.cc
+1
-1
sql/mysqld.cc
sql/mysqld.cc
+16
-5
No files found.
include/my_base.h
View file @
ea3ea9ed
...
@@ -319,6 +319,8 @@ enum ha_base_keytype {
...
@@ -319,6 +319,8 @@ enum ha_base_keytype {
#define SEARCH_NULL_ARE_EQUAL 32768
/* NULL in keys are equal */
#define SEARCH_NULL_ARE_EQUAL 32768
/* NULL in keys are equal */
#define SEARCH_NULL_ARE_NOT_EQUAL 65536
/* NULL in keys are not equal */
#define SEARCH_NULL_ARE_NOT_EQUAL 65536
/* NULL in keys are not equal */
#define SEARCH_RETURN_B_POS (65536*2)
/* see ha_key_cmp for description */
/* bits in opt_flag */
/* bits in opt_flag */
#define QUICK_USED 1
#define QUICK_USED 1
#define READ_CACHE_USED 2
#define READ_CACHE_USED 2
...
...
include/my_handler.h
View file @
ea3ea9ed
...
@@ -63,4 +63,6 @@ extern int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
...
@@ -63,4 +63,6 @@ extern int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
register
uchar
*
b
,
uint
key_length
,
uint
nextflag
,
register
uchar
*
b
,
uint
key_length
,
uint
nextflag
,
uint
*
diff_pos
);
uint
*
diff_pos
);
extern
HA_KEYSEG
*
ha_find_null
(
HA_KEYSEG
*
keyseg
,
uchar
*
a
);
#endif
/* _my_handler_h */
#endif
/* _my_handler_h */
include/myisam.h
View file @
ea3ea9ed
...
@@ -322,7 +322,9 @@ typedef enum
...
@@ -322,7 +322,9 @@ typedef enum
/* Treat NULLs as inequal when collecting statistics (default for 4.1/5.0) */
/* Treat NULLs as inequal when collecting statistics (default for 4.1/5.0) */
MI_STATS_METHOD_NULLS_NOT_EQUAL
,
MI_STATS_METHOD_NULLS_NOT_EQUAL
,
/* Treat NULLs as equal when collecting statistics (like 4.0 did) */
/* Treat NULLs as equal when collecting statistics (like 4.0 did) */
MI_STATS_METHOD_NULLS_EQUAL
MI_STATS_METHOD_NULLS_EQUAL
,
/* Ignore NULLs - count only tuples without NULLs in the index components */
MI_STATS_METHOD_IGNORE_NULLS
}
enum_mi_stats_method
;
}
enum_mi_stats_method
;
typedef
struct
st_mi_check_param
typedef
struct
st_mi_check_param
...
@@ -349,7 +351,14 @@ typedef struct st_mi_check_param
...
@@ -349,7 +351,14 @@ typedef struct st_mi_check_param
int
tmpfile_createflag
;
int
tmpfile_createflag
;
myf
myf_rw
;
myf
myf_rw
;
IO_CACHE
read_cache
;
IO_CACHE
read_cache
;
/*
The next two are used to collect statistics, see update_key_parts for
description.
*/
ulonglong
unique_count
[
MI_MAX_KEY_SEG
+
1
];
ulonglong
unique_count
[
MI_MAX_KEY_SEG
+
1
];
ulonglong
notnull_count
[
MI_MAX_KEY_SEG
+
1
];
ha_checksum
key_crc
[
MI_MAX_POSSIBLE_KEY
];
ha_checksum
key_crc
[
MI_MAX_POSSIBLE_KEY
];
ulong
rec_per_key_part
[
MI_MAX_KEY_SEG
*
MI_MAX_POSSIBLE_KEY
];
ulong
rec_per_key_part
[
MI_MAX_KEY_SEG
*
MI_MAX_POSSIBLE_KEY
];
void
*
thd
;
void
*
thd
;
...
@@ -409,7 +418,8 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
...
@@ -409,7 +418,8 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
my_bool
repair
);
my_bool
repair
);
int
update_state_info
(
MI_CHECK
*
param
,
MI_INFO
*
info
,
uint
update
);
int
update_state_info
(
MI_CHECK
*
param
,
MI_INFO
*
info
,
uint
update
);
void
update_key_parts
(
MI_KEYDEF
*
keyinfo
,
ulong
*
rec_per_key_part
,
void
update_key_parts
(
MI_KEYDEF
*
keyinfo
,
ulong
*
rec_per_key_part
,
ulonglong
*
unique
,
ulonglong
records
);
ulonglong
*
unique
,
ulonglong
*
notnull
,
ulonglong
records
);
int
filecopy
(
MI_CHECK
*
param
,
File
to
,
File
from
,
my_off_t
start
,
int
filecopy
(
MI_CHECK
*
param
,
File
to
,
File
from
,
my_off_t
start
,
my_off_t
length
,
const
char
*
type
);
my_off_t
length
,
const
char
*
type
);
int
movepoint
(
MI_INFO
*
info
,
byte
*
record
,
my_off_t
oldpos
,
int
movepoint
(
MI_INFO
*
info
,
byte
*
record
,
my_off_t
oldpos
,
...
...
myisam/mi_check.c
View file @
ea3ea9ed
...
@@ -391,7 +391,10 @@ int chk_key(MI_CHECK *param, register MI_INFO *info)
...
@@ -391,7 +391,10 @@ int chk_key(MI_CHECK *param, register MI_INFO *info)
found_keys
++
;
found_keys
++
;
param
->
record_checksum
=
init_checksum
;
param
->
record_checksum
=
init_checksum
;
bzero
((
char
*
)
&
param
->
unique_count
,
sizeof
(
param
->
unique_count
));
bzero
((
char
*
)
&
param
->
unique_count
,
sizeof
(
param
->
unique_count
));
bzero
((
char
*
)
&
param
->
notnull_count
,
sizeof
(
param
->
notnull_count
));
if
((
!
(
param
->
testflag
&
T_SILENT
)))
if
((
!
(
param
->
testflag
&
T_SILENT
)))
printf
(
"- check data record references index: %d
\n
"
,
key
+
1
);
printf
(
"- check data record references index: %d
\n
"
,
key
+
1
);
if
(
keyinfo
->
flag
&
HA_FULLTEXT
)
if
(
keyinfo
->
flag
&
HA_FULLTEXT
)
...
@@ -496,7 +499,9 @@ int chk_key(MI_CHECK *param, register MI_INFO *info)
...
@@ -496,7 +499,9 @@ int chk_key(MI_CHECK *param, register MI_INFO *info)
if
(
param
->
testflag
&
T_STATISTICS
)
if
(
param
->
testflag
&
T_STATISTICS
)
update_key_parts
(
keyinfo
,
rec_per_key_part
,
param
->
unique_count
,
update_key_parts
(
keyinfo
,
rec_per_key_part
,
param
->
unique_count
,
(
ulonglong
)
info
->
state
->
records
);
param
->
stats_method
==
MI_STATS_METHOD_IGNORE_NULLS
?
param
->
notnull_count
:
NULL
,
(
ulonglong
)
info
->
state
->
records
);
}
}
if
(
param
->
testflag
&
T_INFO
)
if
(
param
->
testflag
&
T_INFO
)
{
{
...
@@ -552,6 +557,96 @@ err:
...
@@ -552,6 +557,96 @@ err:
return
1
;
return
1
;
}
}
/*
"Ignore NULLs" statistics collection method: process first index tuple.
SYNOPSIS
mi_collect_stats_nonulls_first()
keyseg IN Array of key part descriptions
notnull INOUT Array, notnull[i] = (number of {keypart1...keypart_i}
tuples that don't contain NULLs)
key IN Key values tuple
DESCRIPTION
Process the first index tuple - find out which prefix tuples don't
contain NULLs, and update the array of notnull counters accordingly.
*/
static
void
mi_collect_stats_nonulls_first
(
HA_KEYSEG
*
keyseg
,
ulonglong
*
notnull
,
uchar
*
key
)
{
uint
first_null
,
kp
;
first_null
=
ha_find_null
(
keyseg
,
key
)
-
keyseg
;
/*
All prefix tuples that don't include keypart_{first_null} are not-null
tuples (and all others aren't), increment counters for them.
*/
for
(
kp
=
0
;
kp
<
first_null
;
kp
++
)
notnull
[
kp
]
++
;
}
/*
"Ignore NULLs" statistics collection method: process next index tuple.
SYNOPSIS
mi_collect_stats_nonulls_next()
keyseg IN Array of key part descriptions
notnull INOUT Array, notnull[i] = (number of {keypart1...keypart_i}
tuples that don't contain NULLs)
prev_key IN Previous key values tuple
last_key IN Next key values tuple
DESCRIPTION
Process the next index tuple:
1. Find out which prefix tuples of last_key don't contain NULLs, and
update the array of notnull counters accordingly.
2. Find the first keypart number where the prev_key and last_key tuples
are different(A), or last_key has NULL value(B), and return it, so the
caller can count number of unique tuples for each key prefix. We don't
need (B) to be counted, and that is compensated back in
update_key_parts().
RETURN
1 + number of first keypart where values differ or last_key tuple has NULL
*/
static
int
mi_collect_stats_nonulls_next
(
HA_KEYSEG
*
keyseg
,
ulonglong
*
notnull
,
uchar
*
prev_key
,
uchar
*
last_key
)
{
uint
diffs
[
2
];
uint
first_null_seg
,
kp
;
/*
Find the first keypart where values are different or either of them is
NULL. We get results in diffs array:
diffs[0]= 1 + number of first different keypart
diffs[1]=offset: (last_key + diffs[1]) points to first value in
last_key that is NULL or different from corresponding
value in prev_key.
*/
ha_key_cmp
(
keyseg
,
prev_key
,
last_key
,
USE_WHOLE_KEY
,
SEARCH_FIND
|
SEARCH_NULL_ARE_NOT_EQUAL
|
SEARCH_RETURN_B_POS
,
diffs
);
HA_KEYSEG
*
seg
=
keyseg
+
diffs
[
0
]
-
1
;
/* Find first NULL in last_key */
first_null_seg
=
ha_find_null
(
seg
,
last_key
+
diffs
[
1
])
-
keyseg
;
for
(
kp
=
0
;
kp
<
first_null_seg
;
kp
++
)
notnull
[
kp
]
++
;
/*
Return 1+ number of first key part where values differ. Don't care if
these were NULLs and not .... We compensate for that in
update_key_parts.
*/
return
diffs
[
0
];
}
/* Check if index is ok */
/* Check if index is ok */
static
int
chk_index
(
MI_CHECK
*
param
,
MI_INFO
*
info
,
MI_KEYDEF
*
keyinfo
,
static
int
chk_index
(
MI_CHECK
*
param
,
MI_INFO
*
info
,
MI_KEYDEF
*
keyinfo
,
...
@@ -641,8 +736,20 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
...
@@ -641,8 +736,20 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
ha_key_cmp
(
keyinfo
->
seg
,
info
->
lastkey
,
key
,
USE_WHOLE_KEY
,
ha_key_cmp
(
keyinfo
->
seg
,
info
->
lastkey
,
key
,
USE_WHOLE_KEY
,
SEARCH_FIND
|
SEARCH_NULL_ARE_NOT_EQUAL
,
SEARCH_FIND
|
SEARCH_NULL_ARE_NOT_EQUAL
,
&
diff_pos
);
&
diff_pos
);
else
if
(
param
->
stats_method
==
MI_STATS_METHOD_IGNORE_NULLS
)
{
diff_pos
=
mi_collect_stats_nonulls_next
(
keyinfo
->
seg
,
param
->
notnull_count
,
info
->
lastkey
,
key
);
}
param
->
unique_count
[
diff_pos
-
1
]
++
;
param
->
unique_count
[
diff_pos
-
1
]
++
;
}
}
else
{
if
(
param
->
stats_method
==
MI_STATS_METHOD_IGNORE_NULLS
)
mi_collect_stats_nonulls_first
(
keyinfo
->
seg
,
param
->
notnull_count
,
key
);
}
}
}
(
*
key_checksum
)
+=
mi_byte_checksum
((
byte
*
)
key
,
(
*
key_checksum
)
+=
mi_byte_checksum
((
byte
*
)
key
,
key_length
-
info
->
s
->
rec_reflength
);
key_length
-
info
->
s
->
rec_reflength
);
...
@@ -2088,7 +2195,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
...
@@ -2088,7 +2195,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
if
(
param
->
testflag
&
T_STATISTICS
)
if
(
param
->
testflag
&
T_STATISTICS
)
update_key_parts
(
sort_param
.
keyinfo
,
rec_per_key_part
,
sort_param
.
unique
,
update_key_parts
(
sort_param
.
keyinfo
,
rec_per_key_part
,
sort_param
.
unique
,
(
ulonglong
)
info
->
state
->
records
);
param
->
stats_method
==
MI_STATS_METHOD_IGNORE_NULLS
?
sort_param
.
notnull
:
NULL
,(
ulonglong
)
info
->
state
->
records
);
share
->
state
.
key_map
|=
(
ulonglong
)
1
<<
sort_param
.
key
;
share
->
state
.
key_map
|=
(
ulonglong
)
1
<<
sort_param
.
key
;
if
(
sort_param
.
fix_datafile
)
if
(
sort_param
.
fix_datafile
)
...
@@ -3255,11 +3363,21 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
...
@@ -3255,11 +3363,21 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
ha_key_cmp
(
sort_param
->
seg
,
sort_info
->
key_block
->
lastkey
,
ha_key_cmp
(
sort_param
->
seg
,
sort_info
->
key_block
->
lastkey
,
(
uchar
*
)
a
,
USE_WHOLE_KEY
,
(
uchar
*
)
a
,
USE_WHOLE_KEY
,
SEARCH_FIND
|
SEARCH_NULL_ARE_NOT_EQUAL
,
&
diff_pos
);
SEARCH_FIND
|
SEARCH_NULL_ARE_NOT_EQUAL
,
&
diff_pos
);
else
if
(
param
->
stats_method
==
MI_STATS_METHOD_IGNORE_NULLS
)
{
diff_pos
=
mi_collect_stats_nonulls_next
(
sort_param
->
seg
,
sort_param
->
notnull
,
sort_info
->
key_block
->
lastkey
,
(
uchar
*
)
a
);
}
sort_param
->
unique
[
diff_pos
-
1
]
++
;
sort_param
->
unique
[
diff_pos
-
1
]
++
;
}
}
else
else
{
{
cmp
=
-
1
;
cmp
=
-
1
;
if
(
param
->
stats_method
==
MI_STATS_METHOD_IGNORE_NULLS
)
mi_collect_stats_nonulls_first
(
sort_param
->
seg
,
sort_param
->
notnull
,
(
uchar
*
)
a
);
}
}
if
((
sort_param
->
keyinfo
->
flag
&
HA_NOSAME
)
&&
cmp
==
0
)
if
((
sort_param
->
keyinfo
->
flag
&
HA_NOSAME
)
&&
cmp
==
0
)
{
{
...
@@ -3978,24 +4096,34 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
...
@@ -3978,24 +4096,34 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
/*
/*
Update statistics for each part of an index
Update statistics for each part of an index
SYNOPSIS
SYNOPSIS
update_key_parts()
update_key_parts()
keyinfo
Index information (only key->keysegs used)
keyinfo
IN
Index information (only key->keysegs used)
rec_per_key_part OUT Store statistics here
rec_per_key_part OUT Store statistics here
unique IN Array of
#distinct values collected over index
unique IN Array of
(#distinct tuples)
run.
notnull_tuples IN Array of (#tuples), or NULL
records Number of records in the table
records Number of records in the table
NOTES
DESCRIPTION
This function is called produce index statistics values from unique and
notnull_tuples arrays after these arrays were produced with sequential
index scan (the scan is done in two places: chk_index() and
sort_key_write()).
This function handles all 3 index statistics collection methods.
Unique is an array:
Unique is an array:
unique[0]= (#different values of {keypart1}) - 1
unique[0]= (#different values of {keypart1}) - 1
unique[1]= (#different values of {keypart2,keypart1} tuple) - unique[0] - 1
unique[1]= (#different values of {keypart1,keypart2} tuple)-unique[0]-1
...
...
The 'unique' array is collected in one sequential scan through the entire
index. This is done in two places: in chk_index() and in sort_key_write().
For MI_STATS_METHOD_IGNORE_NULLS method, notnull_tuples is an array too:
Statistics collection may consider NULLs as either equal or unequal (see
notnull_tuples[0]= (#of {keypart1} tuples such that keypart1 is not NULL)
SEARCH_NULL_ARE_NOT_EQUAL, MI_STATS_METHOD_*).
notnull_tuples[1]= (#of {keypart1,keypart2} tuples such that all
keypart{i} are not NULL)
...
For all other statistics collection methods notnull_tuples==NULL.
Output is an array:
Output is an array:
rec_per_key_part[k] =
rec_per_key_part[k] =
...
@@ -4007,25 +4135,53 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
...
@@ -4007,25 +4135,53 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
index tuples}
index tuples}
= #tuples-in-the-index / #distinct-tuples-in-the-index.
= #tuples-in-the-index / #distinct-tuples-in-the-index.
The #tuples-in-the-index and #distinct-tuples-in-the-index have different
meaning depending on which statistics collection method is used:
MI_STATS_METHOD_* how are nulls compared? which tuples are counted?
NULLS_EQUAL NULL == NULL all tuples in table
NULLS_NOT_EQUAL NULL != NULL all tuples in table
IGNORE_NULLS n/a tuples that don't have NULLs
*/
*/
void
update_key_parts
(
MI_KEYDEF
*
keyinfo
,
ulong
*
rec_per_key_part
,
void
update_key_parts
(
MI_KEYDEF
*
keyinfo
,
ulong
*
rec_per_key_part
,
ulonglong
*
unique
,
ulonglong
records
)
ulonglong
*
unique
,
ulonglong
*
notnull
,
ulonglong
records
)
{
{
ulonglong
count
=
0
,
tmp
;
ulonglong
count
=
0
,
tmp
,
unique_tuples
;
ulonglong
tuples
=
records
;
uint
parts
;
uint
parts
;
for
(
parts
=
0
;
parts
<
keyinfo
->
keysegs
;
parts
++
)
for
(
parts
=
0
;
parts
<
keyinfo
->
keysegs
;
parts
++
)
{
{
count
+=
unique
[
parts
];
count
+=
unique
[
parts
];
if
(
count
==
0
)
unique_tuples
=
count
+
1
;
tmp
=
records
;
if
(
notnull
)
{
tuples
=
notnull
[
parts
];
/*
#(unique_tuples not counting tuples with NULLs) =
#(unique_tuples counting tuples with NULLs as different) -
#(tuples with NULLs)
*/
unique_tuples
-=
(
records
-
notnull
[
parts
]);
}
if
(
unique_tuples
==
0
)
tmp
=
1
;
else
if
(
count
==
0
)
tmp
=
tuples
;
/* 1 unique tuple */
else
else
tmp
=
(
records
+
(
count
+
1
)
/
2
)
/
(
count
+
1
);
tmp
=
(
tuples
+
unique_tuples
/
2
)
/
unique_tuples
;
/* for some weird keys (e.g. FULLTEXT) tmp can be <1 here.
let's ensure it is not */
/*
for some weird keys (e.g. FULLTEXT) tmp can be <1 here.
let's ensure it is not
*/
set_if_bigger
(
tmp
,
1
);
set_if_bigger
(
tmp
,
1
);
if
(
tmp
>=
(
ulonglong
)
~
(
ulong
)
0
)
if
(
tmp
>=
(
ulonglong
)
~
(
ulong
)
0
)
tmp
=
(
ulonglong
)
~
(
ulong
)
0
;
tmp
=
(
ulonglong
)
~
(
ulong
)
0
;
*
rec_per_key_part
=
(
ulong
)
tmp
;
*
rec_per_key_part
=
(
ulong
)
tmp
;
rec_per_key_part
++
;
rec_per_key_part
++
;
}
}
...
...
myisam/myisamchk.c
View file @
ea3ea9ed
...
@@ -339,7 +339,8 @@ static struct my_option my_long_options[] =
...
@@ -339,7 +339,8 @@ static struct my_option my_long_options[] =
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"stats_method"
,
OPT_STATS_METHOD
,
{
"stats_method"
,
OPT_STATS_METHOD
,
"Specifies how index statistics collection code should threat NULLs. "
"Specifies how index statistics collection code should threat NULLs. "
"Possible values of name are
\"
nulls_unequal
\"
(default behavior for 4.1/5.0), and
\"
nulls_equal
\"
(emulate 4.0 behavior)."
,
"Possible values of name are
\"
nulls_unequal
\"
(default behavior for 4.1/5.0), "
"
\"
nulls_equal
\"
(emulate 4.0 behavior), and
\"
nulls_ignored
\"
."
,
(
gptr
*
)
&
myisam_stats_method_str
,
(
gptr
*
)
&
myisam_stats_method_str
,
0
,
(
gptr
*
)
&
myisam_stats_method_str
,
(
gptr
*
)
&
myisam_stats_method_str
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
0
,
0
,
0
,
0
,
0
,
0
,
GET_NO_ARG
,
NO_ARG
,
0
,
0
,
0
,
0
,
0
,
0
}
{
0
,
0
,
0
,
0
,
0
,
0
,
GET_NO_ARG
,
NO_ARG
,
0
,
0
,
0
,
0
,
0
,
0
}
...
@@ -451,6 +452,10 @@ static void usage(void)
...
@@ -451,6 +452,10 @@ static void usage(void)
-a, --analyze Analyze distribution of keys. Will make some joins in
\n
\
-a, --analyze Analyze distribution of keys. Will make some joins in
\n
\
MySQL faster. You can check the calculated distribution
\n
\
MySQL faster. You can check the calculated distribution
\n
\
by using '--description --verbose table_name'.
\n
\
by using '--description --verbose table_name'.
\n
\
--stats_method=name Specifies how index statistics collection code should
\n
\
threat NULLs. Possible values of name are
\"
nulls_unequal
\"\n
\
(default for 4.1/5.0),
\"
nulls_equal
\"
(emulate 4.0), and
\n
\
\"
nulls_ignored
\"
.
\n
\
-d, --description Prints some information about table.
\n
\
-d, --description Prints some information about table.
\n
\
-A, --set-auto-increment[=value]
\n
\
-A, --set-auto-increment[=value]
\n
\
Force auto_increment to start at this or higher value
\n
\
Force auto_increment to start at this or higher value
\n
\
...
@@ -472,7 +477,7 @@ static void usage(void)
...
@@ -472,7 +477,7 @@ static void usage(void)
#include <help_end.h>
#include <help_end.h>
const
char
*
myisam_stats_method_names
[]
=
{
"nulls_unequal"
,
"nulls_equal"
,
const
char
*
myisam_stats_method_names
[]
=
{
"nulls_unequal"
,
"nulls_equal"
,
NullS
};
"nulls_ignored"
,
NullS
};
TYPELIB
myisam_stats_method_typelib
=
{
TYPELIB
myisam_stats_method_typelib
=
{
array_elements
(
myisam_stats_method_names
)
-
1
,
""
,
array_elements
(
myisam_stats_method_names
)
-
1
,
""
,
myisam_stats_method_names
,
NULL
};
myisam_stats_method_names
,
NULL
};
...
@@ -699,14 +704,25 @@ get_one_option(int optid,
...
@@ -699,14 +704,25 @@ get_one_option(int optid,
case
OPT_STATS_METHOD
:
case
OPT_STATS_METHOD
:
{
{
int
method
;
int
method
;
enum_mi_stats_method
method_conv
;
myisam_stats_method_str
=
argument
;
myisam_stats_method_str
=
argument
;
if
((
method
=
find_type
(
argument
,
&
myisam_stats_method_typelib
,
2
))
<=
0
)
if
((
method
=
find_type
(
argument
,
&
myisam_stats_method_typelib
,
2
))
<=
0
)
{
{
fprintf
(
stderr
,
"Invalid value of stats_method: %s.
\n
"
,
argument
);
fprintf
(
stderr
,
"Invalid value of stats_method: %s.
\n
"
,
argument
);
exit
(
1
);
exit
(
1
);
}
}
check_param
.
stats_method
=
test
(
method
-
1
)
?
MI_STATS_METHOD_NULLS_EQUAL
:
switch
(
method
-
1
)
{
MI_STATS_METHOD_NULLS_NOT_EQUAL
;
case
0
:
method_conv
=
MI_STATS_METHOD_NULLS_EQUAL
;
break
;
case
1
:
method_conv
=
MI_STATS_METHOD_NULLS_NOT_EQUAL
;
break
;
case
2
:
method_conv
=
MI_STATS_METHOD_IGNORE_NULLS
;
break
;
}
check_param
.
stats_method
=
method_conv
;
break
;
break
;
}
}
#ifdef DEBUG
/* Only useful if debugging */
#ifdef DEBUG
/* Only useful if debugging */
...
...
myisam/myisamdef.h
View file @
ea3ea9ed
...
@@ -297,7 +297,14 @@ typedef struct st_mi_sort_param
...
@@ -297,7 +297,14 @@ typedef struct st_mi_sort_param
pthread_t
thr
;
pthread_t
thr
;
IO_CACHE
read_cache
,
tempfile
,
tempfile_for_exceptions
;
IO_CACHE
read_cache
,
tempfile
,
tempfile_for_exceptions
;
DYNAMIC_ARRAY
buffpek
;
DYNAMIC_ARRAY
buffpek
;
/*
The next two are used to collect statistics, see update_key_parts for
description.
*/
ulonglong
unique
[
MI_MAX_KEY_SEG
+
1
];
ulonglong
unique
[
MI_MAX_KEY_SEG
+
1
];
ulonglong
notnull
[
MI_MAX_KEY_SEG
+
1
];
my_off_t
pos
,
max_pos
,
filepos
,
start_recpos
;
my_off_t
pos
,
max_pos
,
filepos
,
start_recpos
;
uint
key
,
key_length
,
real_key_length
,
sortbuff_size
;
uint
key
,
key_length
,
real_key_length
,
sortbuff_size
;
uint
maxbuffers
,
keys
,
find_length
,
sort_keys_length
;
uint
maxbuffers
,
keys
,
find_length
,
sort_keys_length
;
...
...
myisam/sort.c
View file @
ea3ea9ed
...
@@ -481,8 +481,12 @@ int thr_write_keys(MI_SORT_PARAM *sort_param)
...
@@ -481,8 +481,12 @@ int thr_write_keys(MI_SORT_PARAM *sort_param)
{
{
share
->
state
.
key_map
|=
(
ulonglong
)
1
<<
sinfo
->
key
;
share
->
state
.
key_map
|=
(
ulonglong
)
1
<<
sinfo
->
key
;
if
(
param
->
testflag
&
T_STATISTICS
)
if
(
param
->
testflag
&
T_STATISTICS
)
update_key_parts
(
sinfo
->
keyinfo
,
rec_per_key_part
,
update_key_parts
(
sinfo
->
keyinfo
,
rec_per_key_part
,
sinfo
->
unique
,
sinfo
->
unique
,
(
ulonglong
)
info
->
state
->
records
);
param
->
stats_method
==
MI_STATS_METHOD_IGNORE_NULLS
?
sinfo
->
notnull
:
NULL
,
(
ulonglong
)
info
->
state
->
records
);
if
(
!
sinfo
->
buffpek
.
elements
)
if
(
!
sinfo
->
buffpek
.
elements
)
{
{
if
(
param
->
testflag
&
T_VERBOSE
)
if
(
param
->
testflag
&
T_VERBOSE
)
...
...
mysql-test/r/myisam.result
View file @
ea3ea9ed
...
@@ -670,3 +670,35 @@ show index from t1;
...
@@ -670,3 +670,35 @@ show index from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t1 1 a 1 a A 10 NULL NULL YES BTREE
t1 1 a 1 a A 10 NULL NULL YES BTREE
drop table t1;
drop table t1;
set myisam_stats_method=nulls_ignored;
show variables like 'myisam_stats_method';
Variable_name Value
myisam_stats_method nulls_ignored
create table t1 (
a char(3), b char(4), c char(5), d char(6),
key(a,b,c,d)
);
insert into t1 values ('bcd','def1', NULL, 'zz');
insert into t1 values ('bcd','def2', NULL, 'zz');
insert into t1 values ('bce','def1', 'yuu', NULL);
insert into t1 values ('bce','def2', NULL, 'quux');
analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status OK
show index from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t1 1 a 1 a A 2 NULL NULL YES BTREE
t1 1 a 2 b A 4 NULL NULL YES BTREE
t1 1 a 3 c A 4 NULL NULL YES BTREE
t1 1 a 4 d A 4 NULL NULL YES BTREE
delete from t1;
analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status OK
show index from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t1 1 a 1 a A 0 NULL NULL YES BTREE
t1 1 a 2 b A 0 NULL NULL YES BTREE
t1 1 a 3 c A 0 NULL NULL YES BTREE
t1 1 a 4 d A 0 NULL NULL YES BTREE
set myisam_stats_method=DEFAULT;
mysql-test/t/myisam.test
View file @
ea3ea9ed
...
@@ -637,4 +637,23 @@ show index from t1;
...
@@ -637,4 +637,23 @@ show index from t1;
drop
table
t1
;
drop
table
t1
;
# WL#2609, CSC#XXXX: MyISAM
set
myisam_stats_method
=
nulls_ignored
;
show
variables
like
'myisam_stats_method'
;
create
table
t1
(
a
char
(
3
),
b
char
(
4
),
c
char
(
5
),
d
char
(
6
),
key
(
a
,
b
,
c
,
d
)
);
insert
into
t1
values
(
'bcd'
,
'def1'
,
NULL
,
'zz'
);
insert
into
t1
values
(
'bcd'
,
'def2'
,
NULL
,
'zz'
);
insert
into
t1
values
(
'bce'
,
'def1'
,
'yuu'
,
NULL
);
insert
into
t1
values
(
'bce'
,
'def2'
,
NULL
,
'quux'
);
analyze
table
t1
;
show
index
from
t1
;
delete
from
t1
;
analyze
table
t1
;
show
index
from
t1
;
set
myisam_stats_method
=
DEFAULT
;
# End of 4.1 tests
# End of 4.1 tests
mysys/my_handler.c
View file @
ea3ea9ed
...
@@ -75,7 +75,7 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
...
@@ -75,7 +75,7 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
SYNOPSIS
SYNOPSIS
ha_key_cmp()
ha_key_cmp()
keyseg
K
ey segments of key to compare
keyseg
Array of k
ey segments of key to compare
a First key to compare, in format from _mi_pack_key()
a First key to compare, in format from _mi_pack_key()
This is normally key specified by user
This is normally key specified by user
b Second key to compare. This is always from a row
b Second key to compare. This is always from a row
...
@@ -84,10 +84,32 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
...
@@ -84,10 +84,32 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
next_flag How keys should be compared
next_flag How keys should be compared
If bit SEARCH_FIND is not set the keys includes the row
If bit SEARCH_FIND is not set the keys includes the row
position and this should also be compared
position and this should also be compared
diff_pos OUT Number of first keypart where values differ, counting
from one.
DESCRIPTION
If SEARCH_RETURN_B_POS flag is set, diff_pos must point to array of 2
values, first value has the meaning as described in parameter
description above, the second value is:
diff_pos[1] OUT (b + diff_pos[1]) points to first value in tuple b
that is different from corresponding value in tuple a.
EXAMPLES
Example1: if the function is called for tuples
('aaa','bbb') and ('eee','fff'), then
diff_pos[0] = 1 (as 'aaa' != 'eee')
diff_pos[1] = 0 (offset from beggining of tuple b to 'eee' keypart).
Example2: if the index function is called for tuples
('aaa','bbb') and ('aaa','fff'),
diff_pos[0] = 2 (as 'aaa' != 'eee')
diff_pos[1] = 3 (offset from beggining of tuple b to 'fff' keypart,
here we assume that first key part is CHAR(3) NOT NULL)
NOTES
NOTES
Number-keys can't be splited
Number-keys can't be splited
RETURN VALUES
RETURN VALUES
<0 If a < b
<0 If a < b
0 If a == b
0 If a == b
...
@@ -107,6 +129,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
...
@@ -107,6 +129,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
float
f_1
,
f_2
;
float
f_1
,
f_2
;
double
d_1
,
d_2
;
double
d_1
,
d_2
;
uint
next_key_length
;
uint
next_key_length
;
uchar
*
orig_b
=
b
;
*
diff_pos
=
0
;
*
diff_pos
=
0
;
for
(
;
(
int
)
key_length
>
0
;
key_length
=
next_key_length
,
keyseg
++
)
for
(
;
(
int
)
key_length
>
0
;
key_length
=
next_key_length
,
keyseg
++
)
...
@@ -115,6 +138,9 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
...
@@ -115,6 +138,9 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
uint
piks
=!
(
keyseg
->
flag
&
HA_NO_SORT
);
uint
piks
=!
(
keyseg
->
flag
&
HA_NO_SORT
);
(
*
diff_pos
)
++
;
(
*
diff_pos
)
++
;
if
(
nextflag
&
SEARCH_RETURN_B_POS
)
diff_pos
[
1
]
=
(
uint
)(
b
-
orig_b
);
/* Handle NULL part */
/* Handle NULL part */
if
(
keyseg
->
null_bit
)
if
(
keyseg
->
null_bit
)
{
{
...
@@ -448,3 +474,84 @@ end:
...
@@ -448,3 +474,84 @@ end:
}
}
return
0
;
return
0
;
}
/* ha_key_cmp */
}
/* ha_key_cmp */
/*
Find the first NULL value in index-suffix values tuple
SYNOPSIS
ha_find_null()
keyseg Array of keyparts for key suffix
a Key suffix value tuple
DESCRIPTION
Find the first NULL value in index-suffix values tuple.
TODO Consider optimizing this fuction or its use so we don't search for
NULL values in completely NOT NULL index suffixes.
RETURN
First key part that has NULL as value in values tuple, or the last key part
(with keyseg->type==HA_TYPE_END) if values tuple doesn't contain NULLs.
*/
HA_KEYSEG
*
ha_find_null
(
HA_KEYSEG
*
keyseg
,
uchar
*
a
)
{
for
(;
(
enum
ha_base_keytype
)
keyseg
->
type
!=
HA_KEYTYPE_END
;
keyseg
++
)
{
uchar
*
end
;
if
(
keyseg
->
null_bit
)
{
if
(
!*
a
++
)
return
keyseg
;
}
end
=
a
+
keyseg
->
length
;
switch
((
enum
ha_base_keytype
)
keyseg
->
type
)
{
case
HA_KEYTYPE_TEXT
:
case
HA_KEYTYPE_BINARY
:
if
(
keyseg
->
flag
&
HA_SPACE_PACK
)
{
int
a_length
;
get_key_length
(
a_length
,
a
);
a
+=
a_length
;
break
;
}
else
a
=
end
;
break
;
case
HA_KEYTYPE_VARTEXT
:
case
HA_KEYTYPE_VARBINARY
:
{
int
a_length
;
get_key_length
(
a_length
,
a
);
a
+=
a_length
;
break
;
}
case
HA_KEYTYPE_NUM
:
if
(
keyseg
->
flag
&
HA_SPACE_PACK
)
{
int
alength
=
*
a
++
;
end
=
a
+
alength
;
}
a
=
end
;
break
;
case
HA_KEYTYPE_INT8
:
case
HA_KEYTYPE_SHORT_INT
:
case
HA_KEYTYPE_USHORT_INT
:
case
HA_KEYTYPE_LONG_INT
:
case
HA_KEYTYPE_ULONG_INT
:
case
HA_KEYTYPE_INT24
:
case
HA_KEYTYPE_UINT24
:
#ifdef HAVE_LONG_LONG
case
HA_KEYTYPE_LONGLONG
:
case
HA_KEYTYPE_ULONGLONG
:
#endif
case
HA_KEYTYPE_FLOAT
:
case
HA_KEYTYPE_DOUBLE
:
a
=
end
;
break
;
}
}
return
keyseg
;
}
sql/ha_myisam.cc
View file @
ea3ea9ed
...
@@ -40,7 +40,7 @@ TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
...
@@ -40,7 +40,7 @@ TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
myisam_recover_names
,
NULL
};
myisam_recover_names
,
NULL
};
const
char
*
myisam_stats_method_names
[]
=
{
"nulls_unequal"
,
"nulls_equal"
,
const
char
*
myisam_stats_method_names
[]
=
{
"nulls_unequal"
,
"nulls_equal"
,
NullS
};
"nulls_ignored"
,
NullS
};
TYPELIB
myisam_stats_method_typelib
=
{
TYPELIB
myisam_stats_method_typelib
=
{
array_elements
(
myisam_stats_method_names
)
-
1
,
""
,
array_elements
(
myisam_stats_method_names
)
-
1
,
""
,
myisam_stats_method_names
,
NULL
};
myisam_stats_method_names
,
NULL
};
...
...
sql/mysqld.cc
View file @
ea3ea9ed
...
@@ -5281,7 +5281,8 @@ The minimum value for this variable is 4096.",
...
@@ -5281,7 +5281,8 @@ The minimum value for this variable is 4096.",
GET_ULONG
,
REQUIRED_ARG
,
8192
*
1024
,
4
,
~
0L
,
0
,
1
,
0
},
GET_ULONG
,
REQUIRED_ARG
,
8192
*
1024
,
4
,
~
0L
,
0
,
1
,
0
},
{
"myisam_stats_method"
,
OPT_MYISAM_STATS_METHOD
,
{
"myisam_stats_method"
,
OPT_MYISAM_STATS_METHOD
,
"Specifies how MyISAM index statistics collection code should threat NULLs. "
"Specifies how MyISAM index statistics collection code should threat NULLs. "
"Possible values of name are
\"
nulls_unequal
\"
(default behavior for 4.1/5.0), and
\"
nulls_equal
\"
(emulate 4.0 behavior)."
,
"Possible values of name are
\"
nulls_unequal
\"
(default behavior for 4.1/5.0), "
"
\"
nulls_equal
\"
(emulate 4.0 behavior), and
\"
nulls_ignored
\"
."
,
(
gptr
*
)
&
myisam_stats_method_str
,
(
gptr
*
)
&
myisam_stats_method_str
,
0
,
(
gptr
*
)
&
myisam_stats_method_str
,
(
gptr
*
)
&
myisam_stats_method_str
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"net_buffer_length"
,
OPT_NET_BUFFER_LENGTH
,
{
"net_buffer_length"
,
OPT_NET_BUFFER_LENGTH
,
...
@@ -6475,16 +6476,26 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
...
@@ -6475,16 +6476,26 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
}
}
case
OPT_MYISAM_STATS_METHOD
:
case
OPT_MYISAM_STATS_METHOD
:
{
{
myisam_stats_method_str
=
argument
;
int
method
;
int
method
;
ulong
method_conv
;
myisam_stats_method_str
=
argument
;
if
((
method
=
find_type
(
argument
,
&
myisam_stats_method_typelib
,
2
))
<=
0
)
if
((
method
=
find_type
(
argument
,
&
myisam_stats_method_typelib
,
2
))
<=
0
)
{
{
fprintf
(
stderr
,
"Invalid value of myisam_stats_method: %s.
\n
"
,
argument
);
fprintf
(
stderr
,
"Invalid value of myisam_stats_method: %s.
\n
"
,
argument
);
exit
(
1
);
exit
(
1
);
}
}
global_system_variables
.
myisam_stats_method
=
switch
(
method
-
1
)
{
test
(
method
-
1
)
?
MI_STATS_METHOD_NULLS_EQUAL
:
case
0
:
MI_STATS_METHOD_NULLS_NOT_EQUAL
;
method_conv
=
MI_STATS_METHOD_NULLS_EQUAL
;
break
;
case
1
:
method_conv
=
MI_STATS_METHOD_NULLS_NOT_EQUAL
;
break
;
case
2
:
method_conv
=
MI_STATS_METHOD_IGNORE_NULLS
;
break
;
}
global_system_variables
.
myisam_stats_method
=
method_conv
;
break
;
break
;
}
}
case
OPT_SQL_MODE
:
case
OPT_SQL_MODE
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment