I think you can drop the following indexes as well
CREATE INDEX FirstNameIndex ON PERSON(FirstName);
CREATE INDEX LastNameIndex ON PERSON(LastName);
CREATE INDEX CompanyIndex ON PERSON(Company);

They are redundant in that you have compound indexes that start with each of 
the above. That should improve your insert performance.




--- On Mon, 1/5/09, D. Richard Hipp <[email protected]> wrote:

> From: D. Richard Hipp <[email protected]>
> Subject: Re: [sqlite] Big performance regressions since 3.4.0?
> To: "General Discussion of SQLite Database" <[email protected]>
> Date: Monday, January 5, 2009, 7:16 PM
> Version 3.5.3 made a change to the way DISTINCT is
> processed.   
> Probably that change is making your particular case much
> slower.  The  
> change can be seen at:
> 
>     http://www.sqlite.org/cvstrac/chngview?cn=4538
> 
> This change was in response to grumbling on the mailing
> list
> 
>    
> http://www.mail-archive.com/[email protected]/msg28894.html
> 
> It would appear that I need to spend some time improving
> this  
> optimization - enabling it only in cases where it seems
> likely to  
> improve performance and disabling it in cases like yours
> were it makes  
> things much worse.  We'll try to have a look at that
> for version 3.6.9.
> 
> 
> On Jan 5, 2009, at 7:13 PM, Jason Freund wrote:
> 
> > Dan,
> >
> > Thanks, I sent a separate email containing the source
> and data for  
> > my test app since it's too big (5M) to post to the
> group.   But I'm  
> > also posting just the code for the test app here, in
> case anyone  
> > wants to take a look.  On my target hardware, the
> results I got for  
> > the most egregious regression (doing prepare and step
> on a  
> > selection) were:
> >
> >               3.4.0     3.6.5
> > 100 records     4ms      20ms
> > 500 records    1.4ms     89ms
> > 1000 records   1.5ms     173ms
> >
> > If anyone else is interested in seeing the data to try
> to reproduce  
> > and track the problem, please let me know, and
> I'll send you the  
> > full zip file.
> >
> > Thanks,
> > Jason
> >
> >
> > ===
> > / 
> >
> ******************************************************************************
> > * This app prepares a statement and steps 50 times in
> a database of  
> > 100,
> > * 500 or 1000 records, using a SQL statement that
> seems to demonstrate
> > * a performance regression between 3.4.0 and 3.6.5
> > *
> > * The raw results we got when running this test on
> some cellphone  
> > reference
> > * hardware running an ARM5/~600Mhz chip and NAND
> storage are:
> > *                          3.4.0     3.6.5
> > * N=100, Prepare, StepX50  4ms       20ms
> > * N=500, Prepare, StepX50  1.4ms     89
> > * N=1000 Prepare, StepX50  1.5ms     173ms
> > *
> > * While this test demonstrates the worst degradation:
> constant  
> > performance
> > * for varying data sizes with 3.4.0 and linear
> performance for  
> > 3.6.5, there
> > * were several other test cases that were linear on
> both 340 and  
> > 365, but
> > * were consistently 30% slower for 365.  These other
> cases included a
> > * different query, and a couple of INSERT statements,
> but we didn't
> > * include those results in this test.
> > *
> > * Any advice or insight on this case would be
> appreciated:
> > * [email protected]
> >
> *****************************************************************************/
> >
> > #include <string.h>
> > #include <stdio.h>
> > #include <sqlite3.h>
> > #include <wchar.h>
> > #include <glib.h>
> > #include <sys/time.h>
> >
> > /* Return delta between oldTime - currentTime in
> millisecons */
> > float TimeInterval(struct timeval *oldTvP)
> > {
> >     struct timeval tv;
> >     gettimeofday(&tv, NULL);
> >
> >    if(oldTvP == NULL)
> >        return(0);
> >
> >    tv.tv_sec -= oldTvP->tv_sec;
> >     if (tv.tv_usec < oldTvP->tv_usec) {
> >        tv.tv_usec += 1000000 - oldTvP->tv_usec;
> >             tv.tv_sec--;
> >     } else {
> >        tv.tv_usec -= oldTvP->tv_usec;
> >    }
> >
> >     return (((float)tv.tv_sec*1000) +
> tv.tv_usec/1000.0f);
> > }
> >
> > static int my_utf8_collator(void* user_data, int
> Length1,const void*  
> > Start1,
> >     int Length2, const void* Start2)
> > {
> >    int Result = 0;
> >
> >    gchar* Char1 = (gchar*) Start1;
> >    gchar* Stop1 = Char1 + Length1;
> >    wchar_t Wide1[2] = {0, 0};
> >
> >    gchar* Char2 = (gchar*) Start2;
> >    gchar* Stop2 = Char2 + Length2;
> >    wchar_t Wide2[2] = {0, 0};
> >
> >    while (0 == Result && Char1 < Stop1
> && Char2 < Stop2)
> >    {
> >        Wide1[0] = (wchar_t) g_utf8_get_char(Char1);
> >        Wide2[0] = (wchar_t) g_utf8_get_char(Char2);
> >
> >        Result = wcscoll(Wide1, Wide2);
> >
> >        if (0 == Result)
> >        {
> >            Char1 = g_utf8_next_char(Char1);
> >            Char2 = g_utf8_next_char(Char2);
> >        }
> >    }
> >
> >    if (Result == 0) {
> >      Result = Length1 - Length2;
> >    }
> >
> >    return Result;
> > }
> >
> > void SelectionTest(char *dbName, int category)
> > {
> >     sqlite3 *dbH = NULL;
> >     struct timeval oldTv;
> >     float totalTime=0.0;
> >     const unsigned char *junkStringP = NULL;
> >     char *dummy = NULL, sqlStrP[512];
> >     int sqlErr, loopCount=0, junk;
> >    sqlite3_stmt *stmtP = NULL;
> >    char *selectSql = "SELECT DISTINCT
> PERSON.PersonLUID, FirstName,  
> > LastName, Company, EnglishName, Note NOTNULL,
> SIMPhoneBook,  
> > DisplayNameLast FROM PERSON, _CATEGORY_MEMBERSHIP
> WHERE  
> > _CATEGORY_MEMBERSHIP.EntityLUID = PERSON.PersonLUID
> AND  
> > _CATEGORY_MEMBERSHIP.CategoryLUID = %d ORDER BY
> LastName, FirstName,  
> > Company, SIMPhoneBook, PERSON.PersonLUID COLLATE
> my_utf8_collator  
> > LIMIT 100 OFFSET 0;";
> >    char *selectSql2 = "SELECT DISTINCT
> PERSON.PersonLUID, FirstName,  
> > LastName, Company, EnglishName, Note NOTNULL,
> SIMPhoneBook,  
> > DisplayNameLast FROM PERSON ORDER BY LastName,
> FirstName, Company,  
> > SIMPhoneBook, PERSON.PersonLUID COLLATE
> my_utf8_collator LIMIT 100  
> > OFFSET 0;";
> >
> >     /* Open SQLite database connection */
> >     sqlErr = sqlite3_open(dbName, &dbH);
> >     if (sqlErr) {
> >             printf("sqlite3_open(%s) = 0x%x\n",
> dbName, sqlErr);
> >     }
> >
> >     /* Install user UTF-8 collate function */
> >    sqlErr = sqlite3_create_collation(
> >             dbH, /* (sqlite3 *) */
> >             "my_utf8_collator", /* (const char *)zName
> */
> >             SQLITE_UTF8, /* int enc */
> >             NULL, /* (void *)pCtx */
> >             &my_utf8_collator /* int(xCompare) */
> >     );
> >     if (sqlErr) {
> >             printf("sqlite3_create_collation =
> 0x%x\n", sqlErr);
> >     }
> >
> >     /* Build first SQL statement, with JOIN */
> >     sprintf(sqlStrP, selectSql, category);
> >
> >     /* Start timer, prepare statement and step up to 50
> times */
> >     gettimeofday(&oldTv, NULL);
> >    sqlErr = sqlite3_prepare(dbH, sqlStrP,
> strlen(sqlStrP),
> >             &stmtP, (const char **) &dummy);
> >
> >     while (((sqlErr = sqlite3_step(stmtP)) == SQLITE_ROW)
> && loopCount  
> > < 50) {
> >             /* Include a few column fetches from each row in the
> timing */
> >        junk = sqlite3_column_int(stmtP, 0);
> >        junkStringP = sqlite3_column_text(stmtP, 7);
> >        junk = sqlite3_column_int(stmtP, 6);
> >        junk = sqlite3_column_int(stmtP, 5);
> >
> >             loopCount++;
> >     }
> >
> >     /* Finalize statement, stop timer, and report results
> */
> >     sqlErr = sqlite3_finalize(stmtP);
> >    totalTime = TimeInterval (&oldTv);
> >    printf("A) Create select statement with
> Category and iterate %d "
> >             "times = %3.3f ms\n", loopCount,
> totalTime);
> >
> >     /* Start timer, prepare statement and step up to 50
> times */
> >     gettimeofday(&oldTv, NULL);
> >    sqlErr = sqlite3_prepare(dbH, selectSql2,
> strlen(selectSql2),
> >             &stmtP, (const char **) &dummy);
> >
> >     while (((sqlErr = sqlite3_step(stmtP)) == SQLITE_ROW)
> && loopCount  
> > < 50) {
> >             /* Include a few column fetches from each row in the
> timing */
> >        junk = sqlite3_column_int(stmtP, 0);
> >        junkStringP = sqlite3_column_text(stmtP, 7);
> >        junk = sqlite3_column_int(stmtP, 6);
> >        junk = sqlite3_column_int(stmtP, 5);
> >
> >             loopCount++;
> >     }
> >
> >     /* Finalize statement, stop timer, and report results
> */
> >     sqlErr = sqlite3_finalize(stmtP);
> >    totalTime = TimeInterval (&oldTv);
> >    printf("B) Create select statement (no
> Category) and iterate %d "
> >             "times = %3.3f ms\n\n", loopCount,
> totalTime);
> >
> >     /* Close DB */
> >     sqlErr = sqlite3_close(dbH);
> > }
> >
> > /* Run 3 queries and report timings */
> > int main(int argc, char *argv[])
> > {
> >     const char *versionP;
> >
> >     versionP = sqlite3_libversion();
> >     printf("SQLite %s\n", versionP);
> >
> >    SelectionTest("contacts_100.db",
> -1073743423);
> >    SelectionTest("contacts_500.db",
> -1073743576);
> >    SelectionTest("contacts_1000.db",
> -1073741927);
> >
> >     return 0;
> > }
> >
> > / 
> > *Schema 
> >
> **********************************************************************
> > BEGIN TRANSACTION;
> >
> > CREATE TABLE PERSON(
> >    PersonLUID integer not null primary key,
> >    FirstName text default null collate nocase,
> >    MiddleName text default null,
> >    LastName text default null collate nocase,
> >    Title text default null,
> >    Company text default null collate nocase,
> >    Prefix text default null,
> >    Suffix text default null,
> >    NickName text default null,
> >    EnglishName text default null,
> >    YomiFirstName text default null,
> >    YomiLastName text default null,
> >    YomiCompany text default null,
> >    Ringtone text default null,
> >    VideoRingtone text default null,
> >    Note text default null,
> >
> >     FriendlyName text default null,
> >     DisplayNameLast text default null,
> >     DisplayNameCompany text default null,
> >     DisplayNameFirst text default null,
> >     TwoCharLookup text default null,
> >
> >    Birthday integer default null,
> >    BirthdayAlarm integer default null,
> >    Anniversary integer default null,
> >    AnniversaryAlarm integer default null,
> >
> >    UseCount integer default 0,
> >     DontBeamNote boolean default false,
> >     IsBusinessCard boolean default false,
> >
> >    SIMPhoneBook integer default 0,
> >    SIMEntryID integer default 0
> > );
> >
> > CREATE INDEX FirstNameIndex ON PERSON(FirstName);
> > CREATE INDEX LastNameIndex ON PERSON(LastName);
> > CREATE INDEX CompanyIndex ON PERSON(Company);
> > CREATE INDEX UseCountIndex ON PERSON(UseCount);
> > CREATE INDEX TwoCharLookupIndex ON
> PERSON(TwoCharLookup);
> > CREATE INDEX LastFirstCompanyIndex ON  
> > PERSON(LastName,FirstName,Company,SIMPhoneBook);
> > CREATE INDEX FirstLastCompanyIndex ON  
> > PERSON(FirstName,LastName,Company,SIMPhoneBook);
> > CREATE INDEX CompanyLastFirstIndex ON  
> > PERSON(Company,LastName,FirstName,SIMPhoneBook);
> >
> > CREATE TABLE ADDRESS(
> >     AddressLUID integer primary key default 1,
> >     PersonLUID integer not null,
> >     Identifier text default null,
> >     Address text default null,
> >     City text default null,
> >     State text default null,
> >     PostalCode text default null,
> >     Country text default null,
> >     VCardSrc text default null
> > );
> >
> > CREATE INDEX AddressPersonLUIDIndex ON
> ADDRESS(PersonLUID);
> >
> > CREATE TABLE EXTRAFIELDS(
> >     ExtraFieldLUID integer primary key default 1,
> >     PersonLUID integer not null,
> >     Identifier text default null,
> >     Value text default null,
> >     VCardSrc text default null
> > );
> >
> > CREATE INDEX ExtraFieldPersonLUIDIndex ON
> EXTRAFIELDS(PersonLUID);
> >
> > CREATE TABLE CONTACTS(
> >     ContactLUID integer primary key default 1,
> >     PersonLUID integer not null,
> >     Identifier text default null,
> >     Value text default null,
> >     ContactType text default null,
> >     UseCount integer default 0,
> >     DefaultContact boolean default false,
> >     SpeedDial integer default 0,
> >     VCardSrc text default null
> > );
> >
> > CREATE INDEX ContactPersonLUIDIndex ON
> CONTACTS(PersonLUID);
> >
> > CREATE TABLE THUMBNAIL(
> >     ThumbnailLUID integer primary key default 1,
> >     PersonLUID integer not null,
> >     SmallThumbnail blob not null,
> >     LargeThumbnail blob not null
> > );
> >
> > CREATE INDEX ThumbnailPersonLUIDIndex ON
> THUMBNAIL(PersonLUID);
> >
> > CREATE TABLE CUSTOMLABELS(
> >     CustomLabelLUID integer primary key default 1,
> >     Label text not null,
> >     Identifier text not null
> > );
> >
> > CREATE TABLE VERSION(
> >     Version integer primary key default 1
> > );
> >
> > INSERT INTO VERSION VALUES(3);
> >
> > CREATE TABLE LOADEDDEFAULTS(
> >     HasDefaults integer primary key default 0
> > );
> >
> > CREATE TABLE CATEGORY_RINGTONES(
> >     CategoryLUID integer not null,
> >    Ringtone text default null,
> >     RingtoneType integer default 0
> > );
> >
> > CREATE TABLE RECORD_COUNT_CACHE(
> >     CategoryLUID integer not null primary key,
> >    RecordCount integer default null
> > );
> >
> > CREATE TABLE DISTRIBUTION(
> >     DistributionLUID integer primary key default 1,
> >     Value text not null,
> >     DistributionType text not null
> > );
> >
> > CREATE TABLE DISTRIBUTION_MEMBERSHIP(
> >     MembershipLUID integer primary key default 1,
> >     DistributionLUID integer not null,
> >     PersonLUID integer not null,
> >     Identifier text not null
> > );
> >
> > CREATE INDEX DistMembershipIndex ON  
> >
> DISTRIBUTION_MEMBERSHIP(DistributionLUID,PersonLUID,Identifier);
> >
> > COMMIT;
> >
> > BEGIN TRANSACTION;
> >
> > CREATE TABLE _CATEGORY(
> >     CategoryLUID integer not null primary key default 1,
> >     Name text not null,
> >     ReadOnly int not null
> > );
> >
> > CREATE TABLE _CATEGORY_MEMBERSHIP(
> >     CategoryMemberLUID integer not null primary key
> default 1,
> >     CategoryLUID integer not null,
> >     EntityLUID integer not null
> > );
> >
> > COMMIT;";
> >
> *****************************************************************************/
> >
> >
> > On Dec 25, 2008, at 5:01 AM, Jason Freund wrote:
> >
> >> Hi,
> >>
> >>
> >>
> >> We recently upgraded from 3.4.0 to 3.6.5, and
> noticed that our  
> >> little,
> >> internal sqlite benchmark test program performed
> much worse on most
> >> operations with the new version.  We expected to
> see an improvement
> >> because 3.6.1 advertises a performance enhancement
> with the lookaside
> >> buffer.
> >>
> >>
> >>
> >> Our small performance test app showed regressions
> averaging 25%
> >> slowdown
> >> for all read and write operations, but one test
> case was very
> >> striking:
> >> going from 2ms in 3.4.0 to 170ms in 3.6.5.  This
> test prepared a
> >> "SELECT
> >> DISTINCT from one table with an ORDER BY, COLLATE,
> and LIMIT" and  
> >> then
> >> stepped 50 times through that statement.
> >>
> >>
> >>
> >> I was wondering if anyone else encountered a
> regression, and  
> >> whether I
> >> can interest someone from the dev community in
> looking into it, or
> >> whether I should file a bug?  Also, I may be able
> to do more builds  
> >> to
> >> help isolate when the regressions were introduced,
> but I'm not sure  
> >> if
> >> there is an easy way to download code for earlier
> releases?  I  
> >> haven't
> >> used cvs before - is there an easy way to checkout
> the code for some
> >> kind of "label" that represents an
> official release, or is there a
> >> depot
> >> somewhere that I can just download earlier
> distros?
> >
> > If you post the performance test program I'll take
> a look at it.
> >
> > Dan.
> >
> > _______________________________________________
> > sqlite-users mailing list
> > [email protected]
> >
> http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users
> 
> D. Richard Hipp
> [email protected]
> 
> 
> 
> _______________________________________________
> sqlite-users mailing list
> [email protected]
> http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users
_______________________________________________
sqlite-users mailing list
[email protected]
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to